From b7a51addb22fc2853015e1ad54e8cfee19824ae2 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:44:58 -0800 Subject: [PATCH 01/30] Update backend document service to check for virus scan failures --- .../alcs/src/document/document.service.ts | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/services/apps/alcs/src/document/document.service.ts b/services/apps/alcs/src/document/document.service.ts index 33c028a2b5..2e1259546f 100644 --- a/services/apps/alcs/src/document/document.service.ts +++ b/services/apps/alcs/src/document/document.service.ts @@ -1,11 +1,6 @@ import { CONFIG_TOKEN, IConfig } from '@app/common/config/config.module'; -import { BaseServiceException } from '@app/common/exceptions/base.exception'; -import { - DeleteObjectCommand, - GetObjectCommand, - PutObjectCommand, - S3Client, -} from '@aws-sdk/client-s3'; +import { BaseServiceException, ServiceValidationException } from '@app/common/exceptions/base.exception'; +import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { MultipartFile } from '@fastify/multipart'; import { Inject, Injectable, Logger } from '@nestjs/common'; @@ -167,13 +162,17 @@ export class DocumentService { }); const isInfected = await this.clamAvService.scanFile(fileUrl); + + if (isInfected === null || isInfected === undefined) { + await this.deleteDocument(data.fileKey); + this.logger.warn(`Deleted unscanned file ${data.fileKey}`); + throw new BaseServiceException('Virus scan failed, cannot determine if infected, upload blocked'); + } + if (isInfected) { await this.deleteDocument(data.fileKey); this.logger.warn(`Deleted malicious file ${data.fileKey}`); - throw new BaseServiceException( - 'File may contain malicious data, upload blocked', - 403, - ); + throw new ServiceValidationException('File may contain malicious data, upload blocked'); } return this.documentRepository.save( From 040b1004d17511f794fda24cdc6c1c2d48fb4351 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:54:24 -0800 Subject: [PATCH 02/30] Fix small file name resolution error --- .../decision-document-upload-dialog.component.ts | 2 +- .../decision-document-upload-dialog.component.ts | 2 +- .../decision-document-upload-dialog.component.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts index 651bb281c4..8d8601482c 100644 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts @@ -70,7 +70,7 @@ export class DecisionDocumentUploadDialogComponent implements OnInit { async onSubmit() { const file = this.pendingFile; if (file) { - const renamedFile = new File([file], this.name.value + this.extension ?? file.name, { type: file.type }) + const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); this.isSaving = true; if (this.data.existingDocument) { await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts index 97ada1a8c9..9b73ead50c 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts @@ -69,7 +69,7 @@ export class DecisionDocumentUploadDialogComponent implements OnInit { async onSubmit() { const file = this.pendingFile; if (file) { - const renamedFile = new File([file], this.name.value + this.extension ?? file.name, { type: file.type }); + const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); this.isSaving = true; if (this.data.existingDocument) { await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); diff --git a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts b/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts index 050c883714..97b50b0521 100644 --- a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts @@ -64,7 +64,7 @@ export class DecisionDocumentUploadDialogComponent implements OnInit { async onSubmit() { const file = this.pendingFile; if (file) { - const renamedFile = new File([file], this.name.value + this.extension ?? file.name, { type: file.type }); + const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); this.isSaving = true; if (this.data.existingDocument) { await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); From c0771f3d1529040efd36b20a7443d4492d08ea83 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:33:33 -0800 Subject: [PATCH 03/30] Fix inquiry document service typo --- .../inquiry/documents/documents.component.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts b/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts index b842c43b3f..ad87c325e3 100644 --- a/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts @@ -28,9 +28,9 @@ export class DocumentsComponent implements OnInit { dataSource: MatTableDataSource = new MatTableDataSource(); readonly fileNameTruncLen = FILE_NAME_TRUNCATE_LENGTH; - + constructor( - private planningReviewDocumentService: InquiryDocumentService, + private inquiryDocumentService: InquiryDocumentService, private inquiryDetailService: InquiryDetailService, private confirmationDialogService: ConfirmationDialogService, private toastService: ToastService, @@ -65,15 +65,15 @@ export class DocumentsComponent implements OnInit { } async openFile(uuid: string, fileName: string) { - await this.planningReviewDocumentService.download(uuid, fileName); + await this.inquiryDocumentService.download(uuid, fileName); } async downloadFile(uuid: string, fileName: string) { - await this.planningReviewDocumentService.download(uuid, fileName, false); + await this.inquiryDocumentService.download(uuid, fileName, false); } private async loadDocuments(fileNumber: string) { - this.documents = await this.planningReviewDocumentService.listAll(fileNumber); + this.documents = await this.inquiryDocumentService.listAll(fileNumber); this.dataSource = new MatTableDataSource(this.documents); this.dataSource.sortingDataAccessor = (item, property) => { switch (property) { @@ -112,7 +112,7 @@ export class DocumentsComponent implements OnInit { }) .subscribe(async (accepted) => { if (accepted) { - await this.planningReviewDocumentService.delete(element.uuid); + await this.inquiryDocumentService.delete(element.uuid); this.loadDocuments(this.fileId); this.toastService.showSuccessToast('Document deleted'); } From d6e38de9c2b10b0c833af757ba1dcb4811d6dc99 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:26:38 -0800 Subject: [PATCH 04/30] Move app decision doc upload dialog to shared component --- .../decision-documents.component.ts | 4 +- .../application/decision/decision.module.ts | 2 - .../document-upload-dialog.component.html} | 2 +- .../document-upload-dialog.component.scss | 82 ++++++++++ .../document-upload-dialog.component.spec.ts} | 12 +- .../document-upload-dialog.component.ts | 150 ++++++++++++++++++ alcs-frontend/src/app/shared/shared.module.ts | 4 + 7 files changed, 245 insertions(+), 11 deletions(-) rename alcs-frontend/src/app/{features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html => shared/document-upload-dialog/document-upload-dialog.component.html} (99%) create mode 100644 alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.scss rename alcs-frontend/src/app/{features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts => shared/document-upload-dialog/document-upload-dialog.component.spec.ts} (88%) create mode 100644 alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts index 1435b8b0ef..2735898a4e 100644 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts +++ b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts @@ -8,7 +8,7 @@ import { ApplicationDecisionV2Service } from '../../../../../services/applicatio import { ApplicationDecisionDocumentDto } from '../../../../../services/application/decision/application-decision-v2/application-decision.dto'; import { ToastService } from '../../../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../../../shared/confirmation-dialog/confirmation-dialog.service'; -import { DecisionDocumentUploadDialogComponent } from '../decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component'; +import { DocumentUploadDialogComponent } from '../../../../../shared/document-upload-dialog/document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../../../shared/constants'; @Component({ @@ -102,7 +102,7 @@ export class DecisionDocumentsComponent implements OnInit, OnDestroy { private openFileDialog(existingDocument?: ApplicationDecisionDocumentDto) { if (this.decision) { this.dialog - .open(DecisionDocumentUploadDialogComponent, { + .open(DocumentUploadDialogComponent, { minWidth: '600px', maxWidth: '800px', width: '70%', diff --git a/alcs-frontend/src/app/features/application/decision/decision.module.ts b/alcs-frontend/src/app/features/application/decision/decision.module.ts index 9ae5697437..ddaf336411 100644 --- a/alcs-frontend/src/app/features/application/decision/decision.module.ts +++ b/alcs-frontend/src/app/features/application/decision/decision.module.ts @@ -28,7 +28,6 @@ import { SubdInputComponent } from './decision-v2/decision-input/decision-compon import { DecisionComponentsComponent } from './decision-v2/decision-input/decision-components/decision-components.component'; import { DecisionConditionComponent } from './decision-v2/decision-input/decision-conditions/decision-condition/decision-condition.component'; import { DecisionConditionsComponent } from './decision-v2/decision-input/decision-conditions/decision-conditions.component'; -import { DecisionDocumentUploadDialogComponent } from './decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component'; import { DecisionInputV2Component } from './decision-v2/decision-input/decision-input-v2.component'; import { DecisionV2Component } from './decision-v2/decision-v2.component'; import { ReleaseDialogComponent } from './decision-v2/release-dialog/release-dialog.component'; @@ -72,7 +71,6 @@ export const decisionChildRoutes = [ DecisionConditionDateDialogComponent, DecisionComponentComponent, DecisionComponentsComponent, - DecisionDocumentUploadDialogComponent, RevertToDraftDialogComponent, DecisionDocumentsComponent, NfuInputComponent, diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html similarity index 99% rename from alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html rename to alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html index 7ea010a0d0..e48f0cd1ab 100644 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html @@ -12,7 +12,7 @@

{{ title }} Document

*ngIf="!pendingFile && !existingFile" [ngClass]="{ 'file-drag-drop': true, - error: showVirusError + error: showVirusError, }" class="full-width upload-button" appDragDropFile diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.scss b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.scss new file mode 100644 index 0000000000..85f904a71a --- /dev/null +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.scss @@ -0,0 +1,82 @@ +@use '../../../styles/colors'; + +.form { + display: grid; + grid-template-columns: 1fr 1fr; + row-gap: 32px; + column-gap: 32px; + + .double { + grid-column: 1/3; + } +} + +.full-width { + width: 100%; +} + +a { + word-break: break-all; +} + +.file { + border: 1px solid #000; + border-radius: 8px; + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px; +} + +.upload-button { + margin-top: 6px !important; + + &.error { + border: 2px solid colors.$error-color; + } +} + +.spinner { + display: inline-block; + margin-right: 4px; +} + +:host::ng-deep { + .mdc-button__label { + display: flex; + align-items: center; + } +} + +.file-drag-drop { + background: colors.$white; + border-radius: 4px; + + &:hover { + background: colors.$grey-light !important; + } + + button:nth-child(1) { + width: 100%; + background: colors.$white; + padding: 24px; + border: none; + + &:hover { + background: colors.$grey-light !important; + } + } + + .drag-text { + margin-top: 14px; + color: colors.$grey; + } + + .icon { + color: colors.$grey; + font-size: 36px; + height: 36px; + align-content: center; + margin-bottom: 4px; + } +} diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.spec.ts similarity index 88% rename from alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts rename to alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.spec.ts index 8d8601482c..6e3f34e227 100644 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.spec.ts @@ -2,12 +2,12 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { ApplicationDecisionDocumentDto } from '../../../../../../services/application/decision/application-decision-v2/application-decision-v2.dto'; -import { ApplicationDecisionV2Service } from '../../../../../../services/application/decision/application-decision-v2/application-decision-v2.service'; -import { ToastService } from '../../../../../../services/toast/toast.service'; -import { DOCUMENT_SOURCE } from '../../../../../../shared/document/document.dto'; -import { FileHandle } from '../../../../../../shared/drag-drop-file/drag-drop-file.directive'; -import { splitExtension } from '../../../../../../shared/utils/file'; +import { ApplicationDecisionDocumentDto } from '../../services/application/decision/application-decision-v2/application-decision-v2.dto'; +import { ApplicationDecisionV2Service } from '../../services/application/decision/application-decision-v2/application-decision-v2.service'; +import { ToastService } from '../../services/toast/toast.service'; +import { DOCUMENT_SOURCE } from '../document/document.dto'; +import { FileHandle } from '../drag-drop-file/drag-drop-file.directive'; +import { splitExtension } from '../utils/file'; @Component({ selector: 'app-app-decision-document-upload-dialog', diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts new file mode 100644 index 0000000000..0a93f1e593 --- /dev/null +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -0,0 +1,150 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { ApplicationDecisionDocumentDto } from '../../services/application/decision/application-decision-v2/application-decision-v2.dto'; +import { ApplicationDecisionV2Service } from '../../services/application/decision/application-decision-v2/application-decision-v2.service'; +import { ToastService } from '../../services/toast/toast.service'; +import { DOCUMENT_SOURCE } from '../document/document.dto'; +import { FileHandle } from '../drag-drop-file/drag-drop-file.directive'; +import { splitExtension } from '../utils/file'; + +@Component({ + selector: 'app-document-upload-dialog', + templateUrl: './document-upload-dialog.component.html', + styleUrls: ['./document-upload-dialog.component.scss'], +}) +export class DocumentUploadDialogComponent implements OnInit { + title = 'Create'; + isDirty = false; + isSaving = false; + allowsFileEdit = true; + documentType = 'Decision Package'; + + @Output() uploadFiles: EventEmitter = new EventEmitter(); + + name = new FormControl('', [Validators.required]); + type = new FormControl({ disabled: true, value: undefined }, [Validators.required]); + source = new FormControl({ disabled: true, value: DOCUMENT_SOURCE.ALC }, [Validators.required]); + + visibleToInternal = new FormControl({ disabled: true, value: true }, [Validators.required]); + visibleToPublic = new FormControl({ disabled: true, value: true }, [Validators.required]); + + documentSources = Object.values(DOCUMENT_SOURCE); + + form = new FormGroup({ + name: this.name, + type: this.type, + source: this.source, + visibleToInternal: this.visibleToInternal, + visibleToPublic: this.visibleToPublic, + }); + + pendingFile: File | undefined; + existingFile: string | undefined; + showVirusError = false; + extension = ''; + + constructor( + @Inject(MAT_DIALOG_DATA) + public data: { fileId: string; decisionUuid: string; existingDocument?: ApplicationDecisionDocumentDto }, + protected dialog: MatDialogRef, + private decisionService: ApplicationDecisionV2Service, + private toastService: ToastService, + ) {} + + ngOnInit(): void { + if (this.data.existingDocument) { + const document = this.data.existingDocument; + this.title = 'Edit'; + + const { fileName, extension } = splitExtension(document.fileName); + this.extension = extension; + this.form.patchValue({ + name: fileName, + }); + this.existingFile = document.fileName; + } + } + + async onSubmit() { + const file = this.pendingFile; + if (file) { + const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); + this.isSaving = true; + if (this.data.existingDocument) { + await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); + } + + try { + await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile); + } catch (err) { + this.toastService.showErrorToast('Document upload failed'); + if (err instanceof HttpErrorResponse && err.status === 403) { + this.showVirusError = true; + this.isSaving = false; + this.pendingFile = undefined; + return; + } + } + + this.dialog.close(true); + this.isSaving = false; + } else if (this.data.existingDocument) { + this.isSaving = true; + await this.decisionService.updateFile( + this.data.decisionUuid, + this.data.existingDocument.uuid, + this.name.value! + this.extension, + ); + + this.dialog.close(true); + this.isSaving = false; + } + } + + uploadFile(event: Event) { + const element = event.target as HTMLInputElement; + const selectedFiles = element.files; + if (selectedFiles && selectedFiles[0]) { + this.pendingFile = selectedFiles[0]; + const { fileName, extension } = splitExtension(selectedFiles[0].name); + this.name.setValue(fileName); + this.extension = extension; + this.showVirusError = false; + } + } + + onRemoveFile() { + this.pendingFile = undefined; + this.existingFile = undefined; + this.extension = ''; + this.name.setValue(''); + } + + openFile() { + if (this.pendingFile) { + const fileURL = URL.createObjectURL(this.pendingFile); + window.open(fileURL, '_blank'); + } + } + + async openExistingFile() { + if (this.data.existingDocument) { + await this.decisionService.downloadFile( + this.data.decisionUuid, + this.data.existingDocument.uuid, + this.data.existingDocument.fileName, + ); + } + } + + filesDropped($event: FileHandle) { + this.pendingFile = $event.file; + const { fileName, extension } = splitExtension(this.pendingFile.name); + this.extension = extension; + this.name.setValue(fileName); + this.showVirusError = false; + this.uploadFiles.emit($event); + } +} diff --git a/alcs-frontend/src/app/shared/shared.module.ts b/alcs-frontend/src/app/shared/shared.module.ts index be7cf1ea2f..701c6dabb6 100644 --- a/alcs-frontend/src/app/shared/shared.module.ts +++ b/alcs-frontend/src/app/shared/shared.module.ts @@ -79,6 +79,7 @@ import { MatChipsModule } from '@angular/material/chips'; import { TagChipComponent } from './tags/tag-chip/tag-chip.component'; import { DomSanitizer } from '@angular/platform-browser'; import { CommissionerTagsHeaderComponent } from './tags/commissioner-tags-header/commissioner-tags-header.component'; +import { DocumentUploadDialogComponent } from './document-upload-dialog/document-upload-dialog.component'; @NgModule({ declarations: [ @@ -123,6 +124,7 @@ import { CommissionerTagsHeaderComponent } from './tags/commissioner-tags-header TagsHeaderComponent, TagChipComponent, CommissionerTagsHeaderComponent, + DocumentUploadDialogComponent, ], imports: [ CommonModule, @@ -150,6 +152,7 @@ import { CommissionerTagsHeaderComponent } from './tags/commissioner-tags-header MatSlideToggleModule, MatChipsModule, MatAutocompleteModule, + MatCheckboxModule, ], exports: [ CommonModule, @@ -226,6 +229,7 @@ import { CommissionerTagsHeaderComponent } from './tags/commissioner-tags-header TruncatePipe, TagsHeaderComponent, TagChipComponent, + DocumentUploadDialogComponent, ], }) export class SharedModule { From 33aa818e60af018ee3cfe757105fd716048429b0 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:07:40 -0800 Subject: [PATCH 05/30] Create shared interface for decision services --- .../document-upload-dialog/document-upload.interface.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 alcs-frontend/src/app/shared/document-upload-dialog/document-upload.interface.ts diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload.interface.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload.interface.ts new file mode 100644 index 0000000000..fd143634cc --- /dev/null +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload.interface.ts @@ -0,0 +1,6 @@ +export interface DecisionService { + uploadFile(decisionUuid: string, file: File): Promise; + downloadFile(decisionUuid: string, documentUuid: string, fileName: string, isInline: boolean): Promise; + updateFile(decisionUuid: string, documentUuid: string, fileName: string): Promise; + deleteFile(decisionUuid: string, documentUuid: string): Promise<{ url: string }>; +} From 2ee5e5c38c4c6b6c1c8a8182f3825c011c6f8e3d Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:09:26 -0800 Subject: [PATCH 06/30] Accept any decision service in shared upload dialog --- .../decision-documents.component.ts | 1 + .../document-upload-dialog.component.ts | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts index 2735898a4e..b7742657e0 100644 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts +++ b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts @@ -110,6 +110,7 @@ export class DecisionDocumentsComponent implements OnInit, OnDestroy { fileId: this.fileId, decisionUuid: this.decision?.uuid, existingDocument: existingDocument, + decisionService: this.decisionService, }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts index 0a93f1e593..f59ca7eb07 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -3,11 +3,11 @@ import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ApplicationDecisionDocumentDto } from '../../services/application/decision/application-decision-v2/application-decision-v2.dto'; -import { ApplicationDecisionV2Service } from '../../services/application/decision/application-decision-v2/application-decision-v2.service'; import { ToastService } from '../../services/toast/toast.service'; import { DOCUMENT_SOURCE } from '../document/document.dto'; import { FileHandle } from '../drag-drop-file/drag-drop-file.directive'; import { splitExtension } from '../utils/file'; +import { DecisionService } from './document-upload.interface'; @Component({ selector: 'app-document-upload-dialog', @@ -47,9 +47,13 @@ export class DocumentUploadDialogComponent implements OnInit { constructor( @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; decisionUuid: string; existingDocument?: ApplicationDecisionDocumentDto }, + public data: { + fileId: string; + decisionUuid: string; + existingDocument?: ApplicationDecisionDocumentDto; + decisionService: DecisionService; + }, protected dialog: MatDialogRef, - private decisionService: ApplicationDecisionV2Service, private toastService: ToastService, ) {} @@ -73,11 +77,11 @@ export class DocumentUploadDialogComponent implements OnInit { const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); this.isSaving = true; if (this.data.existingDocument) { - await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); + await this.data.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); } try { - await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile); + await this.data.decisionService.uploadFile(this.data.decisionUuid, renamedFile); } catch (err) { this.toastService.showErrorToast('Document upload failed'); if (err instanceof HttpErrorResponse && err.status === 403) { @@ -92,7 +96,7 @@ export class DocumentUploadDialogComponent implements OnInit { this.isSaving = false; } else if (this.data.existingDocument) { this.isSaving = true; - await this.decisionService.updateFile( + await this.data.decisionService.updateFile( this.data.decisionUuid, this.data.existingDocument.uuid, this.name.value! + this.extension, @@ -131,10 +135,11 @@ export class DocumentUploadDialogComponent implements OnInit { async openExistingFile() { if (this.data.existingDocument) { - await this.decisionService.downloadFile( + await this.data.decisionService.downloadFile( this.data.decisionUuid, this.data.existingDocument.uuid, this.data.existingDocument.fileName, + true, ); } } From 3cabbb2916150293a24138fc0604e1139824ab78 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:22:46 -0800 Subject: [PATCH 07/30] Use shared upload component and pass in decision service for PR's and NOI's --- .../decision-documents/decision-documents.component.ts | 7 ++++--- .../decision-documents/decision-documents.component.ts | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts index 3bcbfb3485..fc0259e865 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts @@ -10,8 +10,8 @@ import { } from '../../../../../services/notice-of-intent/decision-v2/notice-of-intent-decision.dto'; import { ToastService } from '../../../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../../../shared/confirmation-dialog/confirmation-dialog.service'; -import { DecisionDocumentUploadDialogComponent } from '../decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../../../shared/constants'; +import { DocumentUploadDialogComponent } from '../../../../../shared/document-upload-dialog/document-upload-dialog.component'; @Component({ selector: 'app-decision-documents', @@ -37,7 +37,7 @@ export class DecisionDocumentsComponent implements OnInit, OnDestroy { dataSource = new MatTableDataSource(); readonly fileNameTruncLen = FILE_NAME_TRUNCATE_LENGTH; - + constructor( private decisionService: NoticeOfIntentDecisionV2Service, private dialog: MatDialog, @@ -85,7 +85,7 @@ export class DecisionDocumentsComponent implements OnInit, OnDestroy { private openFileDialog(existingDocument?: NoticeOfIntentDecisionDocumentDto) { if (this.decision) { this.dialog - .open(DecisionDocumentUploadDialogComponent, { + .open(DocumentUploadDialogComponent, { minWidth: '600px', maxWidth: '800px', width: '70%', @@ -93,6 +93,7 @@ export class DecisionDocumentsComponent implements OnInit, OnDestroy { fileId: this.fileId, decisionUuid: this.decision?.uuid, existingDocument: existingDocument, + decisionService: this.decisionService, }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/planning-review/decision/decision-documents/decision-documents.component.ts b/alcs-frontend/src/app/features/planning-review/decision/decision-documents/decision-documents.component.ts index 0428b65070..f704bbf285 100644 --- a/alcs-frontend/src/app/features/planning-review/decision/decision-documents/decision-documents.component.ts +++ b/alcs-frontend/src/app/features/planning-review/decision/decision-documents/decision-documents.component.ts @@ -10,8 +10,8 @@ import { import { PlanningReviewDecisionService } from '../../../../services/planning-review/planning-review-decision/planning-review-decision.service'; import { ToastService } from '../../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../../shared/confirmation-dialog/confirmation-dialog.service'; -import { DecisionDocumentUploadDialogComponent } from '../decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../../shared/constants'; +import { DocumentUploadDialogComponent } from '../../../../shared/document-upload-dialog/document-upload-dialog.component'; @Component({ selector: 'app-decision-documents', @@ -35,7 +35,7 @@ export class DecisionDocumentsComponent implements OnDestroy, OnChanges { new MatTableDataSource(); readonly fileNameTruncLen = FILE_NAME_TRUNCATE_LENGTH; - + constructor( private decisionService: PlanningReviewDecisionService, private dialog: MatDialog, @@ -67,7 +67,7 @@ export class DecisionDocumentsComponent implements OnDestroy, OnChanges { private openFileDialog(existingDocument?: PlanningReviewDecisionDocumentDto) { if (this.decision) { this.dialog - .open(DecisionDocumentUploadDialogComponent, { + .open(DocumentUploadDialogComponent, { minWidth: '600px', maxWidth: '800px', width: '70%', @@ -75,6 +75,7 @@ export class DecisionDocumentsComponent implements OnDestroy, OnChanges { fileId: this.fileId, decisionUuid: this.decision?.uuid, existingDocument: existingDocument, + decisionService: this.decisionService, }, }) .beforeClosed() From 5626bff59b6e87f3a00a34b17e46feca1a3261cf Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:26:06 -0800 Subject: [PATCH 08/30] Add missed interface and fix reference --- .../document-upload-dialog/document-upload-dialog.component.ts | 2 +- ...-upload.interface.ts => document-upload-dialog.interface.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename alcs-frontend/src/app/shared/document-upload-dialog/{document-upload.interface.ts => document-upload-dialog.interface.ts} (100%) diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts index f59ca7eb07..1d7a780e93 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -7,7 +7,7 @@ import { ToastService } from '../../services/toast/toast.service'; import { DOCUMENT_SOURCE } from '../document/document.dto'; import { FileHandle } from '../drag-drop-file/drag-drop-file.directive'; import { splitExtension } from '../utils/file'; -import { DecisionService } from './document-upload.interface'; +import { DecisionService } from './document-upload-dialog.interface'; @Component({ selector: 'app-document-upload-dialog', diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload.interface.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.interface.ts similarity index 100% rename from alcs-frontend/src/app/shared/document-upload-dialog/document-upload.interface.ts rename to alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.interface.ts From 6e6d5be20ddade3f5206f3f3dfbbbb5724beecd3 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:39:58 -0800 Subject: [PATCH 09/30] Clean up unused NOI/PR dialogs --- ...sion-document-upload-dialog.component.html | 111 ------------- ...sion-document-upload-dialog.component.scss | 82 ---------- ...n-document-upload-dialog.component.spec.ts | 49 ------ ...cision-document-upload-dialog.component.ts | 150 ------------------ .../decision/decision.module.ts | 2 - ...sion-document-upload-dialog.component.html | 102 ------------ ...sion-document-upload-dialog.component.scss | 82 ---------- ...n-document-upload-dialog.component.spec.ts | 49 ------ ...cision-document-upload-dialog.component.ts | 145 ----------------- .../decision/decision.module.ts | 2 - 10 files changed, 774 deletions(-) delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts delete mode 100644 alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html delete mode 100644 alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html deleted file mode 100644 index 7ea010a0d0..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html +++ /dev/null @@ -1,111 +0,0 @@ -
-

{{ title }} Document

-
-
-
-
-
- Document Upload* -
- -
- -
or drag and drop them here
- -
-
-
- {{ pendingFile.name }} -  ({{ pendingFile.size | filesize }}) -
- -
-
- - -
- - warning A virus was detected in the file. Choose another file and try again. - -
- -
- - Document Name - - {{ extension }} - -
- -
- - -
-
- - Source - - {{ source }} - - -
-
- Visible To: -
- Applicant, L/FNG, and Commissioner -
-
- Public -
-
-
- - -
- - - -
-
-
diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss deleted file mode 100644 index 27b3b52f32..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss +++ /dev/null @@ -1,82 +0,0 @@ -@use '../../../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts deleted file mode 100644 index 10697accdf..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { NoticeOfIntentDecisionV2Service } from '../../../../../../services/notice-of-intent/decision-v2/notice-of-intent-decision-v2.service'; -import { ToastService } from '../../../../../../services/toast/toast.service'; - -import { DecisionDocumentUploadDialogComponent } from './decision-document-upload-dialog.component'; - -describe('DecisionDocumentUploadDialogComponent', () => { - let component: DecisionDocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockNOIDecService: DeepMocked; - - beforeEach(async () => { - mockNOIDecService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DecisionDocumentUploadDialogComponent], - providers: [ - { - provide: NoticeOfIntentDecisionV2Service, - useValue: mockNOIDecService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DecisionDocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts deleted file mode 100644 index 9b73ead50c..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { NoticeOfIntentDecisionV2Service } from '../../../../../../services/notice-of-intent/decision-v2/notice-of-intent-decision-v2.service'; -import { NoticeOfIntentDecisionDocumentDto } from '../../../../../../services/notice-of-intent/decision-v2/notice-of-intent-decision.dto'; -import { ToastService } from '../../../../../../services/toast/toast.service'; -import { DOCUMENT_SOURCE } from '../../../../../../shared/document/document.dto'; -import { FileHandle } from '../../../../../../shared/drag-drop-file/drag-drop-file.directive'; -import { splitExtension } from '../../../../../../shared/utils/file'; - -@Component({ - selector: 'app-noi-decision-document-upload-dialog', - templateUrl: './decision-document-upload-dialog.component.html', - styleUrls: ['./decision-document-upload-dialog.component.scss'], -}) -export class DecisionDocumentUploadDialogComponent implements OnInit { - title = 'Create'; - isDirty = false; - isSaving = false; - allowsFileEdit = true; - documentType = 'Decision Package'; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - name = new FormControl('', [Validators.required]); - type = new FormControl({ disabled: true, value: undefined }, [Validators.required]); - source = new FormControl({ disabled: true, value: DOCUMENT_SOURCE.ALC }, [Validators.required]); - - visibleToInternal = new FormControl({ disabled: true, value: true }, [Validators.required]); - visibleToPublic = new FormControl({ disabled: true, value: true }, [Validators.required]); - - documentSources = Object.values(DOCUMENT_SOURCE); - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - visibleToInternal: this.visibleToInternal, - visibleToPublic: this.visibleToPublic, - }); - - pendingFile: File | undefined; - existingFile: string | undefined; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; decisionUuid: string; existingDocument?: NoticeOfIntentDecisionDocumentDto }, - protected dialog: MatDialogRef, - private decisionService: NoticeOfIntentDecisionV2Service, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - this.form.patchValue({ - name: fileName, - }); - this.existingFile = document.fileName; - } - } - - async onSubmit() { - const file = this.pendingFile; - if (file) { - const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); - this.isSaving = true; - if (this.data.existingDocument) { - await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); - } - - try { - await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - - this.dialog.close(true); - this.isSaving = false; - } else if (this.data.existingDocument) { - this.isSaving = true; - await this.decisionService.updateFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.name.value! + this.extension, - ); - - this.dialog.close(true); - this.isSaving = false; - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - this.pendingFile = selectedFiles[0]; - - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.name.setValue(fileName); - this.extension = extension; - this.showVirusError = false; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.decisionService.downloadFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.data.existingDocument.fileName, - ); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } -} diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision.module.ts b/alcs-frontend/src/app/features/notice-of-intent/decision/decision.module.ts index 505be59742..8abc523ea5 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision.module.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/decision/decision.module.ts @@ -17,7 +17,6 @@ import { RosoInputComponent } from './decision-v2/decision-input/decision-compon import { DecisionComponentsComponent } from './decision-v2/decision-input/decision-components/decision-components.component'; import { DecisionConditionComponent } from './decision-v2/decision-input/decision-conditions/decision-condition/decision-condition.component'; import { DecisionConditionsComponent } from './decision-v2/decision-input/decision-conditions/decision-conditions.component'; -import { DecisionDocumentUploadDialogComponent } from './decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component'; import { DecisionInputV2Component } from './decision-v2/decision-input/decision-input-v2.component'; import { DecisionV2Component } from './decision-v2/decision-v2.component'; import { ReleaseDialogComponent } from './decision-v2/release-dialog/release-dialog.component'; @@ -59,7 +58,6 @@ export const decisionChildRoutes = [ ReleaseDialogComponent, DecisionComponentComponent, DecisionComponentsComponent, - DecisionDocumentUploadDialogComponent, RevertToDraftDialogComponent, DecisionDocumentsComponent, DecisionConditionComponent, diff --git a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html b/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html deleted file mode 100644 index 380a50982f..0000000000 --- a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.html +++ /dev/null @@ -1,102 +0,0 @@ -
-

{{ title }} Document

-
-
-
-
-
- Document Upload* -
- -
- -
or drag and drop them here
- -
-
-
- {{ pendingFile.name }} -  ({{ pendingFile.size | filesize }}) -
- -
-
- - -
- - warning A virus was detected in the file. Choose another file and try again. - -
- -
- - Document Name - - {{ extension }} - -
- -
- - -
-
- - Source - - {{ source }} - - -
-
- - -
- - - -
-
-
diff --git a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss b/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss deleted file mode 100644 index 5a86cf7e2c..0000000000 --- a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss +++ /dev/null @@ -1,82 +0,0 @@ -@use '../../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} \ No newline at end of file diff --git a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts deleted file mode 100644 index 33c3c65019..0000000000 --- a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { PlanningReviewDecisionService } from '../../../../../services/planning-review/planning-review-decision/planning-review-decision.service'; -import { ToastService } from '../../../../../services/toast/toast.service'; - -import { DecisionDocumentUploadDialogComponent } from './decision-document-upload-dialog.component'; - -describe('DecisionDocumentUploadDialogComponent', () => { - let component: DecisionDocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockPRDecService: DeepMocked; - - beforeEach(async () => { - mockPRDecService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DecisionDocumentUploadDialogComponent], - providers: [ - { - provide: PlanningReviewDecisionService, - useValue: mockPRDecService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DecisionDocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts b/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts deleted file mode 100644 index 97b50b0521..0000000000 --- a/alcs-frontend/src/app/features/planning-review/decision/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { PlanningReviewDecisionDocumentDto } from '../../../../../services/planning-review/planning-review-decision/planning-review-decision.dto'; -import { PlanningReviewDecisionService } from '../../../../../services/planning-review/planning-review-decision/planning-review-decision.service'; -import { ToastService } from '../../../../../services/toast/toast.service'; -import { DOCUMENT_SOURCE } from '../../../../../shared/document/document.dto'; -import { FileHandle } from '../../../../../shared/drag-drop-file/drag-drop-file.directive'; -import { splitExtension } from '../../../../../shared/utils/file'; - -@Component({ - selector: 'app-app-decision-document-upload-dialog', - templateUrl: './decision-document-upload-dialog.component.html', - styleUrls: ['./decision-document-upload-dialog.component.scss'], -}) -export class DecisionDocumentUploadDialogComponent implements OnInit { - title = 'Create'; - isDirty = false; - isSaving = false; - allowsFileEdit = true; - documentType = 'Decision Package'; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - name = new FormControl('', [Validators.required]); - type = new FormControl({ disabled: true, value: undefined }, [Validators.required]); - source = new FormControl({ disabled: true, value: DOCUMENT_SOURCE.ALC }, [Validators.required]); - - documentSources = Object.values(DOCUMENT_SOURCE); - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - }); - - pendingFile: File | undefined; - existingFile: string | undefined; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; decisionUuid: string; existingDocument?: PlanningReviewDecisionDocumentDto }, - protected dialog: MatDialogRef, - private decisionService: PlanningReviewDecisionService, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - this.form.patchValue({ - name: fileName, - }); - this.existingFile = document.fileName; - } - } - - async onSubmit() { - const file = this.pendingFile; - if (file) { - const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); - this.isSaving = true; - if (this.data.existingDocument) { - await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); - } - - try { - await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - - this.dialog.close(true); - this.isSaving = false; - } else if (this.data.existingDocument) { - this.isSaving = true; - await this.decisionService.updateFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.name.value! + this.extension, - ); - - this.dialog.close(true); - this.isSaving = false; - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - this.pendingFile = selectedFiles[0]; - - const { fileName, extension } = splitExtension(selectedFiles[0].name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.decisionService.downloadFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.data.existingDocument.fileName, - ); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } -} diff --git a/alcs-frontend/src/app/features/planning-review/decision/decision.module.ts b/alcs-frontend/src/app/features/planning-review/decision/decision.module.ts index be0cf9b7a4..d923cf225a 100644 --- a/alcs-frontend/src/app/features/planning-review/decision/decision.module.ts +++ b/alcs-frontend/src/app/features/planning-review/decision/decision.module.ts @@ -4,7 +4,6 @@ import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { SharedModule } from '../../../shared/shared.module'; import { DecisionDocumentsComponent } from './decision-documents/decision-documents.component'; -import { DecisionDocumentUploadDialogComponent } from './decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component'; import { DecisionInputComponent } from './decision-input/decision-input.component'; import { DecisionComponent } from './decision.component'; import { ReleaseDialogComponent } from './release-dialog/release-dialog.component'; @@ -39,7 +38,6 @@ export const decisionChildRoutes = [ DecisionDocumentsComponent, RevertToDraftDialogComponent, ReleaseDialogComponent, - DecisionDocumentUploadDialogComponent, ], imports: [SharedModule, RouterModule.forChild(decisionChildRoutes), MatTabsModule, MatOptionModule], }) From 3aee92a055a3a359e495121aa8ff2ac72467048f Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:22:48 -0800 Subject: [PATCH 10/30] Update shared upload dialog for use in apps documents and use there --- .../documents/documents.component.ts | 30 ++- .../document-upload-dialog.component.html | 40 ++- .../document-upload-dialog.component.ts | 227 +++++++++++++++--- .../document-upload-dialog.dto.ts | 44 ++++ .../document-upload-dialog.interface.ts | 10 + 5 files changed, 316 insertions(+), 35 deletions(-) create mode 100644 alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts diff --git a/alcs-frontend/src/app/features/application/documents/documents.component.ts b/alcs-frontend/src/app/features/application/documents/documents.component.ts index 3bf2cd2ab0..f8200be725 100644 --- a/alcs-frontend/src/app/features/application/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/application/documents/documents.component.ts @@ -11,8 +11,10 @@ import { ApplicationDocumentDto } from '../../../services/application/applicatio import { ApplicationDocumentService } from '../../../services/application/application-document/application-document.service'; import { ToastService } from '../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../shared/confirmation-dialog/confirmation-dialog.service'; -import { DocumentUploadDialogComponent } from './document-upload-dialog/document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../shared/constants'; +import { ApplicationSubmissionService } from '../../../services/application/application-submission/application-submission.service'; +import { ApplicationParcelService } from '../../../services/application/application-parcel/application-parcel.service'; +import { DocumentUploadDialogComponent } from '../../../shared/document-upload-dialog/document-upload-dialog.component'; @Component({ selector: 'app-documents', @@ -39,7 +41,9 @@ export class DocumentsComponent implements OnInit { private applicationDocumentService: ApplicationDocumentService, private applicationDetailService: ApplicationDetailService, private confirmationDialogService: ConfirmationDialogService, + private applicationSubmissionService: ApplicationSubmissionService, private applicationSubmissionStatusService: ApplicationSubmissionStatusService, + private applicationParcelService: ApplicationParcelService, private toastService: ToastService, public dialog: MatDialog, ) {} @@ -56,6 +60,9 @@ export class DocumentsComponent implements OnInit { } async onUploadFile() { + const submission = await this.applicationSubmissionService.fetchSubmission(this.fileId); + const parcels = await this.applicationParcelService.fetchParcels(this.fileId); + this.dialog .open(DocumentUploadDialogComponent, { minWidth: '600px', @@ -63,6 +70,14 @@ export class DocumentsComponent implements OnInit { width: '70%', data: { fileId: this.fileId, + documentService: this.applicationDocumentService, + selectableParcels: parcels.map((parcel, index) => ({ ...parcel, index })), + selectableOwners: submission.owners + .filter((owner) => owner.type.code === 'ORGZ') + .map((owner) => ({ + label: owner.organizationName ?? owner.displayName, + uuid: owner.uuid, + })), }, }) .beforeClosed() @@ -95,7 +110,10 @@ export class DocumentsComponent implements OnInit { this.dataSource.sort = this.sort; } - onEditFile(element: ApplicationDocumentDto) { + async onEditFile(element: ApplicationDocumentDto) { + const submission = await this.applicationSubmissionService.fetchSubmission(this.fileId); + const parcels = await this.applicationParcelService.fetchParcels(this.fileId); + this.dialog .open(DocumentUploadDialogComponent, { minWidth: '600px', @@ -104,6 +122,14 @@ export class DocumentsComponent implements OnInit { data: { fileId: this.fileId, existingDocument: element, + documentService: this.applicationDocumentService, + selectableParcels: parcels.map((parcel, index) => ({ ...parcel, index })), + selectableOwners: submission.owners + .filter((owner) => owner.type.code === 'ORGZ') + .map((owner) => ({ + label: owner.organizationName ?? owner.displayName, + uuid: owner.uuid, + })), }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html index e48f0cd1ab..2f8236b88e 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html @@ -39,13 +39,14 @@

{{ title }} Document

+ warning A virus was detected in the file. Choose another file and try again. @@ -61,14 +62,21 @@

{{ title }} Document

+ + + warning A virus was detected in the file. Choose another file and try again. +
@@ -78,6 +86,28 @@

{{ title }} Document

+
+ + Associated Parcel + + + #{{ parcel.index + 1 }} PID: + {{ parcel.pid | mask: '000-000-000' }} + No Data + + +
+
+ + Associated Organization + + + {{ owner.label }} + + + +
Visible To:
diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts index 1d7a780e93..7e9ef75b5d 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -1,35 +1,48 @@ import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, Inject, OnDestroy, OnInit, Output } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { ApplicationDecisionDocumentDto } from '../../services/application/decision/application-decision-v2/application-decision-v2.dto'; import { ToastService } from '../../services/toast/toast.service'; -import { DOCUMENT_SOURCE } from '../document/document.dto'; +import { DOCUMENT_SOURCE, DOCUMENT_SYSTEM, DOCUMENT_TYPE, DocumentTypeDto } from '../document/document.dto'; import { FileHandle } from '../drag-drop-file/drag-drop-file.directive'; import { splitExtension } from '../utils/file'; -import { DecisionService } from './document-upload-dialog.interface'; +import { DecisionService, DocumentService } from './document-upload-dialog.interface'; +import { + CreateDocumentDto, + DocumentDto, + SelectableOwnerDto, + SelectableParcelDto, + UpdateDocumentDto, +} from './document-upload-dialog.dto'; +import { Subject } from 'rxjs'; @Component({ selector: 'app-document-upload-dialog', templateUrl: './document-upload-dialog.component.html', styleUrls: ['./document-upload-dialog.component.scss'], }) -export class DocumentUploadDialogComponent implements OnInit { +export class DocumentUploadDialogComponent implements OnInit, OnDestroy { + $destroy = new Subject(); + DOCUMENT_TYPE = DOCUMENT_TYPE; + title = 'Create'; isDirty = false; isSaving = false; allowsFileEdit = true; - documentType = 'Decision Package'; @Output() uploadFiles: EventEmitter = new EventEmitter(); name = new FormControl('', [Validators.required]); - type = new FormControl({ disabled: true, value: undefined }, [Validators.required]); - source = new FormControl({ disabled: true, value: DOCUMENT_SOURCE.ALC }, [Validators.required]); + type = new FormControl(undefined, [Validators.required]); + source = new FormControl('', [Validators.required]); + + parcelId = new FormControl(null); + ownerId = new FormControl(null); - visibleToInternal = new FormControl({ disabled: true, value: true }, [Validators.required]); - visibleToPublic = new FormControl({ disabled: true, value: true }, [Validators.required]); + visibleToInternal = new FormControl(false, [Validators.required]); + visibleToPublic = new FormControl(false, [Validators.required]); + documentTypes: DocumentTypeDto[] = []; documentSources = Object.values(DOCUMENT_SOURCE); form = new FormGroup({ @@ -38,10 +51,13 @@ export class DocumentUploadDialogComponent implements OnInit { source: this.source, visibleToInternal: this.visibleToInternal, visibleToPublic: this.visibleToPublic, + parcelId: this.parcelId, + ownerId: this.ownerId, }); pendingFile: File | undefined; - existingFile: string | undefined; + existingFile: { name: string; size: number } | undefined; + showSupersededWarning = false; showVirusError = false; extension = ''; @@ -49,39 +65,102 @@ export class DocumentUploadDialogComponent implements OnInit { @Inject(MAT_DIALOG_DATA) public data: { fileId: string; - decisionUuid: string; - existingDocument?: ApplicationDecisionDocumentDto; - decisionService: DecisionService; + decisionUuid?: string; + existingDocument?: DocumentDto; + decisionService?: DecisionService; + documentService?: DocumentService; + selectableParcels?: SelectableParcelDto[]; + selectableOwners?: SelectableOwnerDto[]; }, protected dialog: MatDialogRef, private toastService: ToastService, ) {} ngOnInit(): void { + this.loadDocumentTypes(); + if (this.data.existingDocument) { const document = this.data.existingDocument; this.title = 'Edit'; + this.allowsFileEdit = !!(this.data.decisionService || document.system === DOCUMENT_SYSTEM.ALCS); + + if (document.type?.code === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { + this.prepareCertificateOfTitleUpload(document.uuid); + this.allowsFileEdit = false; + } + if (document.type?.code === DOCUMENT_TYPE.CORPORATE_SUMMARY) { + this.prepareCorporateSummaryUpload(document.uuid); + this.allowsFileEdit = false; + } const { fileName, extension } = splitExtension(document.fileName); this.extension = extension; + this.form.patchValue({ name: fileName, + source: document.source, + visibleToInternal: document.visibilityFlags?.includes('C') || document.visibilityFlags?.includes('A'), + visibleToPublic: document.visibilityFlags?.includes('P'), }); - this.existingFile = document.fileName; + + this.existingFile = { name: document.fileName, size: 0 }; + + if (this.data.documentService) { + this.type.setValue(document.type!.code); + } + } + + if (this.data.decisionService) { + this.type.disable(); + this.source.disable(); + this.visibleToInternal.disable(); + this.visibleToPublic.disable(); + + this.type.setValue(DOCUMENT_TYPE.DECISION_DOCUMENT); + this.source.setValue(DOCUMENT_SOURCE.ALC); + this.visibleToInternal.setValue(true); + this.visibleToPublic.setValue(true); } } async onSubmit() { const file = this.pendingFile; + const visibilityFlags: ('A' | 'C' | 'G' | 'P')[] = []; + + if (this.visibleToInternal.getRawValue()) { + visibilityFlags.push('A'); + visibilityFlags.push('G'); + visibilityFlags.push('C'); + } + + if (this.visibleToPublic.getRawValue()) { + visibilityFlags.push('P'); + } + + const dto: UpdateDocumentDto = { + fileName: this.name.value! + this.extension, + source: this.source.value as DOCUMENT_SOURCE, + typeCode: this.type.value as DOCUMENT_TYPE, + visibilityFlags, + parcelUuid: this.parcelId.value ?? undefined, + ownerUuid: this.ownerId.value ?? undefined, + }; + if (file) { const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); this.isSaving = true; if (this.data.existingDocument) { - await this.data.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); + if (this.data.decisionService && this.data.decisionUuid) { + this.data.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); + } } try { - await this.data.decisionService.uploadFile(this.data.decisionUuid, renamedFile); + if (this.data.decisionService && this.data.decisionUuid) { + await this.data.decisionService.uploadFile(this.data.decisionUuid, renamedFile); + } else if (this.data.documentService) { + await this.data.documentService.upload(this.data.fileId, { ...dto, file } as CreateDocumentDto); + } } catch (err) { this.toastService.showErrorToast('Document upload failed'); if (err instanceof HttpErrorResponse && err.status === 403) { @@ -96,17 +175,79 @@ export class DocumentUploadDialogComponent implements OnInit { this.isSaving = false; } else if (this.data.existingDocument) { this.isSaving = true; - await this.data.decisionService.updateFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.name.value! + this.extension, - ); + if (this.data.decisionService && this.data.decisionUuid) { + await this.data.decisionService.updateFile( + this.data.decisionUuid, + this.data.existingDocument.uuid, + this.name.value! + this.extension, + ); + } else if (this.data.documentService) { + this.data.documentService.update(this.data.existingDocument.uuid, dto); + } this.dialog.close(true); this.isSaving = false; } } + async prepareCertificateOfTitleUpload(uuid?: string) { + if (this.data.selectableParcels && this.data.selectableParcels.length > 0) { + this.parcelId.setValidators([Validators.required]); + this.parcelId.updateValueAndValidity(); + this.source.setValue(DOCUMENT_SOURCE.APPLICANT); + + const selectedParcel = this.data.selectableParcels.find((parcel) => parcel.certificateOfTitleUuid === uuid); + if (selectedParcel) { + this.parcelId.setValue(selectedParcel.uuid); + } else if (uuid) { + this.showSupersededWarning = true; + } + } + } + + async prepareCorporateSummaryUpload(uuid?: string) { + if (this.data.selectableOwners && this.data.selectableOwners.length > 0) { + this.ownerId.setValidators([Validators.required]); + this.ownerId.updateValueAndValidity(); + this.source.setValue(DOCUMENT_SOURCE.APPLICANT); + + const selectedOwner = this.data.selectableOwners.find((owner) => owner.corporateSummaryUuid === uuid); + if (selectedOwner) { + this.ownerId.setValue(selectedOwner.uuid); + } else if (uuid) { + this.showSupersededWarning = true; + } + } + } + + async onDocTypeSelected($event?: DocumentTypeDto) { + if (this.type.value === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { + await this.prepareCertificateOfTitleUpload(); + this.visibleToInternal.setValue(true); + } else { + this.parcelId.setValue(null); + this.parcelId.setValidators([]); + this.parcelId.updateValueAndValidity(); + } + + if (this.type.value === DOCUMENT_TYPE.CORPORATE_SUMMARY) { + await this.prepareCorporateSummaryUpload(); + this.visibleToInternal.setValue(true); + } else { + this.ownerId.setValue(null); + this.ownerId.setValidators([]); + this.ownerId.updateValueAndValidity(); + } + } + + filterDocumentTypes(term: string, item: DocumentTypeDto) { + const termLower = term.toLocaleLowerCase(); + return ( + item.label.toLocaleLowerCase().indexOf(termLower) > -1 || + item.oatsCode.toLocaleLowerCase().indexOf(termLower) > -1 + ); + } + uploadFile(event: Event) { const element = event.target as HTMLInputElement; const selectedFiles = element.files; @@ -135,12 +276,20 @@ export class DocumentUploadDialogComponent implements OnInit { async openExistingFile() { if (this.data.existingDocument) { - await this.data.decisionService.downloadFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.data.existingDocument.fileName, - true, - ); + if (this.data.decisionService && this.data.decisionUuid) { + await this.data.decisionService.downloadFile( + this.data.decisionUuid, + this.data.existingDocument.uuid, + this.data.existingDocument.fileName, + true, + ); + } else if (this.data.documentService) { + await this.data.documentService.download( + this.data.existingDocument.uuid, + this.data.existingDocument.fileName, + true, + ); + } } } @@ -152,4 +301,26 @@ export class DocumentUploadDialogComponent implements OnInit { this.showVirusError = false; this.uploadFiles.emit($event); } + + private async loadDocumentTypes() { + if (this.data.documentService) { + const docTypes = await this.data.documentService.fetchTypes(); + docTypes.sort((a, b) => (a.label > b.label ? 1 : -1)); + this.documentTypes = docTypes.filter((type) => type.code !== DOCUMENT_TYPE.ORIGINAL_APPLICATION); + } else if (this.data.decisionService) { + this.documentTypes = [ + { + code: DOCUMENT_TYPE.DECISION_DOCUMENT, + label: 'Decision Package', + description: '', + oatsCode: '', + }, + ]; + } + } + + ngOnDestroy(): void { + this.$destroy.next(); + this.$destroy.complete(); + } } diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts new file mode 100644 index 0000000000..20aee8bad8 --- /dev/null +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts @@ -0,0 +1,44 @@ +import { DOCUMENT_SOURCE, DOCUMENT_SYSTEM, DOCUMENT_TYPE, DocumentTypeDto } from '../../shared/document/document.dto'; + +export interface UpdateDocumentDto { + file?: File; + parcelUuid?: string; + ownerUuid?: string; + fileName: string; + typeCode: DOCUMENT_TYPE; + source: DOCUMENT_SOURCE; + visibilityFlags: ('A' | 'C' | 'G' | 'P')[]; +} + +export interface CreateDocumentDto extends UpdateDocumentDto { + file: File; +} + +export interface DocumentDto { + uuid: string; + documentUuid: string; + type?: DocumentTypeDto; + description?: string; + visibilityFlags?: string[]; + source: DOCUMENT_SOURCE; + system: DOCUMENT_SYSTEM; + fileName: string; + mimeType: string; + uploadedBy: string; + uploadedAt: number; + evidentiaryRecordSorting?: number; + fileSize?: number; +} + +export interface SelectableParcelDto { + uuid: string; + pid: string; + certificateOfTitleUuid: string; + index: string; +} + +export interface SelectableOwnerDto { + label: string; + uuid: string; + corporateSummaryUuid: string; +} diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.interface.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.interface.ts index fd143634cc..388f12d61c 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.interface.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.interface.ts @@ -1,6 +1,16 @@ +import { DocumentTypeDto } from '../document/document.dto'; +import { CreateDocumentDto, UpdateDocumentDto } from './document-upload-dialog.dto'; + export interface DecisionService { uploadFile(decisionUuid: string, file: File): Promise; downloadFile(decisionUuid: string, documentUuid: string, fileName: string, isInline: boolean): Promise; updateFile(decisionUuid: string, documentUuid: string, fileName: string): Promise; deleteFile(decisionUuid: string, documentUuid: string): Promise<{ url: string }>; } + +export interface DocumentService { + update(uuid: string, updateDto: UpdateDocumentDto): Promise; + upload(fileNumber: string, createDto: CreateDocumentDto): Promise; + download(uuid: string, fileName: string, isInline: boolean): Promise; + fetchTypes(): Promise; +} From 5f7d97999e41c7fbfaf1fbcb5971001d2fae5964 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:26:48 -0800 Subject: [PATCH 11/30] Clean up more unused dialogs --- .../application/application.module.ts | 2 - ...sion-document-upload-dialog.component.scss | 82 ----- ...n-document-upload-dialog.component.spec.ts | 49 --- .../document-upload-dialog.component.html | 142 --------- .../document-upload-dialog.component.scss | 88 ------ .../document-upload-dialog.component.spec.ts | 63 ---- .../document-upload-dialog.component.ts | 297 ------------------ 7 files changed, 723 deletions(-) delete mode 100644 alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.html delete mode 100644 alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.ts diff --git a/alcs-frontend/src/app/features/application/application.module.ts b/alcs-frontend/src/app/features/application/application.module.ts index e347318a34..826bf2f72d 100644 --- a/alcs-frontend/src/app/features/application/application.module.ts +++ b/alcs-frontend/src/app/features/application/application.module.ts @@ -15,7 +15,6 @@ import { appChildRoutes, ApplicationComponent } from './application.component'; import { BoundaryAmendmentComponent } from './boundary-amendment/boundary-amendment.component'; import { EditBoundaryAmendmentDialogComponent } from './boundary-amendment/edit-boundary-amendment-dialog/edit-boundary-amendment-dialog.component'; import { DecisionModule } from './decision/decision.module'; -import { DocumentUploadDialogComponent } from './documents/document-upload-dialog/document-upload-dialog.component'; import { DocumentsComponent } from './documents/documents.component'; import { InfoRequestsComponent } from './info-requests/info-requests.component'; import { InfoRequestDialogComponent } from './info-requests/info-request-dialog/info-request-dialog.component'; @@ -73,7 +72,6 @@ const routes: Routes = [ ApplicantInfoComponent, LfngInfoComponent, DocumentsComponent, - DocumentUploadDialogComponent, ProposalComponent, NfuProposalComponent, SubdProposalComponent, diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss deleted file mode 100644 index 7c95496402..0000000000 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.scss +++ /dev/null @@ -1,82 +0,0 @@ -@use '../../../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} \ No newline at end of file diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts deleted file mode 100644 index 759e0e8534..0000000000 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-input/decision-file-upload-dialog/decision-document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { ApplicationDecisionV2Service } from '../../../../../../services/application/decision/application-decision-v2/application-decision-v2.service'; -import { ToastService } from '../../../../../../services/toast/toast.service'; - -import { DecisionDocumentUploadDialogComponent } from './decision-document-upload-dialog.component'; - -describe('DecisionDocumentUploadDialogComponent', () => { - let component: DecisionDocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockAppDecService: DeepMocked; - - beforeEach(async () => { - mockAppDecService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DecisionDocumentUploadDialogComponent], - providers: [ - { - provide: ApplicationDecisionV2Service, - useValue: mockAppDecService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DecisionDocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.html deleted file mode 100644 index e3b824a029..0000000000 --- a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.html +++ /dev/null @@ -1,142 +0,0 @@ -
-

{{ title }} Document

- Superseded - Not associated with Applicant Submission in Portal -
-
-
-
-
- Document Upload* -
- -
- -
or drag and drop them here
- -
-
-
- {{ pendingFile.name }} -  ({{ pendingFile.size | filesize }}) -
- -
-
-
- {{ existingFile.name }} -  ({{ existingFile.size | filesize }}) -
- -
- - warning A virus was detected in the file. Choose another file and try again. - -
- -
- - Document Name - - {{ extension }} - -
- -
- - -
-
- - Source - - {{ source }} - - -
-
- - Associated Parcel - - - #{{ parcel.index + 1 }} PID: - {{ parcel.pid | mask: '000-000-000' }} - No Data - - -
-
- - Associated Organization - - - {{ owner.label }} - - - -
-
- Visible To: -
- Applicant, L/FNG, and Commissioner -
-
- Public -
-
-
- - -
- - - -
-
-
diff --git a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.scss b/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.scss deleted file mode 100644 index ba93743c38..0000000000 --- a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.scss +++ /dev/null @@ -1,88 +0,0 @@ -@use '../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.superseded-warning { - background-color: colors.$secondary-color-dark; - color: #fff; - padding: 0 4px; -} - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} \ No newline at end of file diff --git a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.spec.ts deleted file mode 100644 index 88572c1418..0000000000 --- a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { ApplicationDocumentService } from '../../../../services/application/application-document/application-document.service'; -import { ApplicationParcelService } from '../../../../services/application/application-parcel/application-parcel.service'; -import { ApplicationSubmissionService } from '../../../../services/application/application-submission/application-submission.service'; -import { ToastService } from '../../../../services/toast/toast.service'; - -import { DocumentUploadDialogComponent } from './document-upload-dialog.component'; - -describe('DocumentUploadDialogComponent', () => { - let component: DocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockAppDocService: DeepMocked; - let mockParcelService: DeepMocked; - let mockSubmissionService: DeepMocked; - - beforeEach(async () => { - mockAppDocService = createMock(); - mockParcelService = createMock(); - mockSubmissionService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DocumentUploadDialogComponent], - providers: [ - { - provide: ApplicationDocumentService, - useValue: mockAppDocService, - }, - { - provide: ApplicationParcelService, - useValue: mockParcelService, - }, - { - provide: ApplicationSubmissionService, - useValue: mockSubmissionService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.ts deleted file mode 100644 index 793a43da4a..0000000000 --- a/alcs-frontend/src/app/features/application/documents/document-upload-dialog/document-upload-dialog.component.ts +++ /dev/null @@ -1,297 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Subject } from 'rxjs'; -import { - ApplicationDocumentDto, - UpdateDocumentDto, -} from '../../../../services/application/application-document/application-document.dto'; -import { ApplicationDocumentService } from '../../../../services/application/application-document/application-document.service'; -import { ApplicationParcelService } from '../../../../services/application/application-parcel/application-parcel.service'; -import { ApplicationSubmissionService } from '../../../../services/application/application-submission/application-submission.service'; -import { ToastService } from '../../../../services/toast/toast.service'; -import { - DOCUMENT_SOURCE, - DOCUMENT_SYSTEM, - DOCUMENT_TYPE, - DocumentTypeDto, -} from '../../../../shared/document/document.dto'; -import { splitExtension } from '../../../../shared/utils/file'; -import { FileHandle } from '../../../../shared/drag-drop-file/drag-drop-file.directive'; - -@Component({ - selector: 'app-document-upload-dialog', - templateUrl: './document-upload-dialog.component.html', - styleUrls: ['./document-upload-dialog.component.scss'], -}) -export class DocumentUploadDialogComponent implements OnInit, OnDestroy { - $destroy = new Subject(); - DOCUMENT_TYPE = DOCUMENT_TYPE; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - title = 'Create'; - isDirty = false; - isSaving = false; - allowsFileEdit = true; - documentTypeAhead: string | undefined = undefined; - - name = new FormControl('', [Validators.required]); - type = new FormControl(undefined, [Validators.required]); - source = new FormControl('', [Validators.required]); - - parcelId = new FormControl(null); - ownerId = new FormControl(null); - - visibleToInternal = new FormControl(false, [Validators.required]); - visibleToPublic = new FormControl(false, [Validators.required]); - - documentTypes: DocumentTypeDto[] = []; - documentSources = Object.values(DOCUMENT_SOURCE); - selectableParcels: { uuid: string; index: number; pid?: string }[] = []; - selectableOwners: { uuid: string; label: string }[] = []; - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - visibleToInternal: this.visibleToInternal, - visibleToPublic: this.visibleToPublic, - parcelId: this.parcelId, - ownerId: this.ownerId, - }); - - pendingFile: File | undefined; - existingFile: { name: string; size: number } | undefined; - showSupersededWarning = false; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; existingDocument?: ApplicationDocumentDto }, - protected dialog: MatDialogRef, - private applicationDocumentService: ApplicationDocumentService, - private parcelService: ApplicationParcelService, - private submissionService: ApplicationSubmissionService, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - this.loadDocumentTypes(); - - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - this.allowsFileEdit = document.system === DOCUMENT_SYSTEM.ALCS; - if (document.type?.code === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { - this.prepareCertificateOfTitleUpload(document.uuid); - this.allowsFileEdit = false; - } - if (document.type?.code === DOCUMENT_TYPE.CORPORATE_SUMMARY) { - this.allowsFileEdit = false; - this.prepareCorporateSummaryUpload(document.uuid); - } - - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - this.form.patchValue({ - name: fileName, - type: document.type?.code, - source: document.source, - visibleToInternal: document.visibilityFlags.includes('C') || document.visibilityFlags.includes('A'), - visibleToPublic: document.visibilityFlags.includes('P'), - }); - this.documentTypeAhead = document.type!.code; - this.existingFile = { - name: document.fileName, - size: 0, - }; - } - } - - async onSubmit() { - const visibilityFlags: ('A' | 'C' | 'G' | 'P')[] = []; - - if (this.visibleToInternal.getRawValue()) { - visibilityFlags.push('A'); - visibilityFlags.push('G'); - visibilityFlags.push('C'); - } - - if (this.visibleToPublic.getRawValue()) { - visibilityFlags.push('P'); - } - - const file = this.pendingFile; - const dto: UpdateDocumentDto = { - fileName: this.name.value! + this.extension, - source: this.source.value as DOCUMENT_SOURCE, - typeCode: this.type.value as DOCUMENT_TYPE, - visibilityFlags, - parcelUuid: this.parcelId.value ?? undefined, - ownerUuid: this.ownerId.value ?? undefined, - file, - }; - - this.isSaving = true; - if (this.data.existingDocument) { - await this.applicationDocumentService.update(this.data.existingDocument.uuid, dto); - } else if (file !== undefined) { - try { - await this.applicationDocumentService.upload(this.data.fileId, { - ...dto, - file, - }); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - this.showVirusError = false; - } - - this.dialog.close(true); - this.isSaving = false; - } - - ngOnDestroy(): void { - this.$destroy.next(); - this.$destroy.complete(); - } - - filterDocumentTypes(term: string, item: DocumentTypeDto) { - const termLower = term.toLocaleLowerCase(); - return ( - item.label.toLocaleLowerCase().indexOf(termLower) > -1 || - item.oatsCode.toLocaleLowerCase().indexOf(termLower) > -1 - ); - } - - async prepareCertificateOfTitleUpload(uuid?: string) { - const parcels = await this.parcelService.fetchParcels(this.data.fileId); - if (parcels.length > 0) { - this.parcelId.setValidators([Validators.required]); - this.parcelId.updateValueAndValidity(); - this.source.setValue(DOCUMENT_SOURCE.APPLICANT); - - const selectedParcel = parcels.find((parcel) => parcel.certificateOfTitleUuid === uuid); - if (selectedParcel) { - this.parcelId.setValue(selectedParcel.uuid); - } else if (uuid) { - this.showSupersededWarning = true; - } - - this.selectableParcels = parcels.map((parcel, index) => ({ - uuid: parcel.uuid, - pid: parcel.pid, - index: index, - })); - } - } - - async prepareCorporateSummaryUpload(uuid?: string) { - const submission = await this.submissionService.fetchSubmission(this.data.fileId); - if (submission.owners.length > 0) { - const owners = submission.owners; - this.ownerId.setValidators([Validators.required]); - this.ownerId.updateValueAndValidity(); - this.source.setValue(DOCUMENT_SOURCE.APPLICANT); - - const selectedOwner = owners.find((owner) => owner.corporateSummaryUuid === uuid); - if (selectedOwner) { - this.ownerId.setValue(selectedOwner.uuid); - } else if (uuid) { - this.showSupersededWarning = true; - } - - this.selectableOwners = owners - .filter((owner) => owner.type.code === 'ORGZ') - .map((owner, index) => ({ - label: owner.organizationName ?? owner.displayName, - uuid: owner.uuid, - })); - } - } - - async onDocTypeSelected($event?: DocumentTypeDto) { - if ($event) { - this.type.setValue($event.code); - } else { - this.type.setValue(undefined); - } - - if (this.type.value === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { - await this.prepareCertificateOfTitleUpload(); - this.visibleToInternal.setValue(true); - } else { - this.parcelId.setValue(null); - this.parcelId.setValidators([]); - this.parcelId.updateValueAndValidity(); - } - - if (this.type.value === DOCUMENT_TYPE.CORPORATE_SUMMARY) { - await this.prepareCorporateSummaryUpload(); - this.visibleToInternal.setValue(true); - } else { - this.ownerId.setValue(null); - this.ownerId.setValidators([]); - this.ownerId.updateValueAndValidity(); - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - this.pendingFile = selectedFiles[0]; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.applicationDocumentService.download( - this.data.existingDocument.uuid, - this.data.existingDocument.fileName, - ); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } - - private async loadDocumentTypes() { - const docTypes = await this.applicationDocumentService.fetchTypes(); - docTypes.sort((a, b) => (a.label > b.label ? 1 : -1)); - this.documentTypes = docTypes.filter((type) => type.code !== DOCUMENT_TYPE.ORIGINAL_APPLICATION); - } -} From af00a17d6b21a60e088b7fe83b8df179087b895f Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:56:25 -0800 Subject: [PATCH 12/30] Use shared upload dialog in inquiries - Remove old dialog - Swap to new one - Remove old one from module - Only show owners/parcels if provided --- .../document-upload-dialog.component.html | 108 ---------- .../document-upload-dialog.component.scss | 89 -------- .../document-upload-dialog.component.spec.ts | 49 ----- .../document-upload-dialog.component.ts | 191 ------------------ .../inquiry/documents/documents.component.ts | 4 +- .../app/features/inquiry/inquiry.module.ts | 2 - .../document-upload-dialog.component.html | 4 +- 7 files changed, 5 insertions(+), 442 deletions(-) delete mode 100644 alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.html delete mode 100644 alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.ts diff --git a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.html deleted file mode 100644 index fdc228b65b..0000000000 --- a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.html +++ /dev/null @@ -1,108 +0,0 @@ -
-

{{ title }} Document

-
-
-
-
-
- Document Upload* -
- -
- -
or drag and drop them here
- -
-
-
- {{ pendingFile.name }} -  ({{ pendingFile.size | filesize }}) -
- -
-
-
- {{ existingFile.name }} -  ({{ existingFile.size | filesize }}) -
- -
- - warning A virus was detected in the file. Choose another file and try again. - -
- -
- - Document Name - - {{ extension }} - -
- -
- - -
-
- - Source - - {{ source }} - - -
-
- - -
- - - -
-
-
diff --git a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.scss b/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.scss deleted file mode 100644 index fcdc947261..0000000000 --- a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.scss +++ /dev/null @@ -1,89 +0,0 @@ -@use '../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.superseded-warning { - background-color: colors.$secondary-color-dark; - color: #fff; - padding: 0 4px; -} - - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} \ No newline at end of file diff --git a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.spec.ts deleted file mode 100644 index 1571be1108..0000000000 --- a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { InquiryDocumentService } from '../../../../services/inquiry/inquiry-document/inquiry-document.service'; -import { ToastService } from '../../../../services/toast/toast.service'; - -import { DocumentUploadDialogComponent } from './document-upload-dialog.component'; - -describe('DocumentUploadDialogComponent', () => { - let component: DocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockAppDocService: DeepMocked; - - beforeEach(async () => { - mockAppDocService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DocumentUploadDialogComponent], - providers: [ - { - provide: InquiryDocumentService, - useValue: mockAppDocService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.ts deleted file mode 100644 index 1b0c751f46..0000000000 --- a/alcs-frontend/src/app/features/inquiry/documents/document-upload-dialog/document-upload-dialog.component.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Subject } from 'rxjs'; -import { - InquiryDocumentDto, - UpdateDocumentDto, -} from '../../../../services/inquiry/inquiry-document/inquiry-document.dto'; -import { InquiryDocumentService } from '../../../../services/inquiry/inquiry-document/inquiry-document.service'; -import { ToastService } from '../../../../services/toast/toast.service'; -import { - DOCUMENT_SOURCE, - DOCUMENT_SYSTEM, - DOCUMENT_TYPE, - DocumentTypeDto, -} from '../../../../shared/document/document.dto'; -import { splitExtension } from '../../../../shared/utils/file'; -import { FileHandle } from '../../../../shared/drag-drop-file/drag-drop-file.directive'; - -@Component({ - selector: 'app-document-upload-dialog', - templateUrl: './document-upload-dialog.component.html', - styleUrls: ['./document-upload-dialog.component.scss'], -}) -export class DocumentUploadDialogComponent implements OnInit, OnDestroy { - $destroy = new Subject(); - DOCUMENT_TYPE = DOCUMENT_TYPE; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - title = 'Create'; - isDirty = false; - isSaving = false; - allowsFileEdit = true; - documentTypeAhead: string | undefined = undefined; - - name = new FormControl('', [Validators.required]); - type = new FormControl(undefined, [Validators.required]); - source = new FormControl('', [Validators.required]); - - documentTypes: DocumentTypeDto[] = []; - documentSources = Object.values(DOCUMENT_SOURCE); - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - }); - - pendingFile: File | undefined; - existingFile: { name: string; size: number } | undefined; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; existingDocument?: InquiryDocumentDto }, - protected dialog: MatDialogRef, - private inquiryDocumentService: InquiryDocumentService, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - this.loadDocumentTypes(); - - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - this.allowsFileEdit = document.system === DOCUMENT_SYSTEM.ALCS; - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - - this.form.patchValue({ - name: fileName, - type: document.type?.code, - source: document.source, - }); - this.documentTypeAhead = document.type!.code; - - this.existingFile = { - name: document.fileName, - size: 0, - }; - } - } - - async onSubmit() { - const file = this.pendingFile; - const dto: UpdateDocumentDto = { - fileName: this.name.value! + this.extension, - source: this.source.value as DOCUMENT_SOURCE, - typeCode: this.type.value as DOCUMENT_TYPE, - file, - }; - - this.isSaving = true; - if (this.data.existingDocument) { - await this.inquiryDocumentService.update(this.data.existingDocument.uuid, dto); - } else if (file !== undefined) { - try { - await this.inquiryDocumentService.upload(this.data.fileId, { - ...dto, - file, - }); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - this.showVirusError = false; - } - - this.dialog.close(true); - this.isSaving = false; - } - - ngOnDestroy(): void { - this.$destroy.next(); - this.$destroy.complete(); - } - - filterDocumentTypes(term: string, item: DocumentTypeDto) { - const termLower = term.toLocaleLowerCase(); - return ( - item.label.toLocaleLowerCase().indexOf(termLower) > -1 || - item.oatsCode.toLocaleLowerCase().indexOf(termLower) > -1 - ); - } - - async onDocTypeSelected($event?: DocumentTypeDto) { - if ($event) { - this.type.setValue($event.code); - } else { - this.type.setValue(undefined); - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - this.pendingFile = selectedFiles[0]; - - const documentName = selectedFiles[0].name; - const { fileName, extension } = splitExtension(documentName); - this.name.setValue(fileName); - this.extension = extension; - this.showVirusError = false; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.inquiryDocumentService.download(this.data.existingDocument.uuid, this.data.existingDocument.fileName); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } - - private async loadDocumentTypes() { - const docTypes = await this.inquiryDocumentService.fetchTypes(); - docTypes.sort((a, b) => (a.label > b.label ? 1 : -1)); - this.documentTypes = docTypes.filter((type) => type.code !== DOCUMENT_TYPE.ORIGINAL_APPLICATION); - } -} diff --git a/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts b/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts index ad87c325e3..902eb78d0a 100644 --- a/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/inquiry/documents/documents.component.ts @@ -9,8 +9,8 @@ import { PlanningReviewDocumentDto } from '../../../services/planning-review/pla import { ToastService } from '../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../shared/confirmation-dialog/confirmation-dialog.service'; import { DOCUMENT_SYSTEM } from '../../../shared/document/document.dto'; -import { DocumentUploadDialogComponent } from './document-upload-dialog/document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../shared/constants'; +import { DocumentUploadDialogComponent } from '../../../shared/document-upload-dialog/document-upload-dialog.component'; @Component({ selector: 'app-documents', @@ -54,6 +54,7 @@ export class DocumentsComponent implements OnInit { width: '70%', data: { fileId: this.fileId, + documentService: this.inquiryDocumentService, }, }) .beforeClosed() @@ -95,6 +96,7 @@ export class DocumentsComponent implements OnInit { data: { fileId: this.fileId, existingDocument: element, + documentService: this.inquiryDocumentService, }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/inquiry/inquiry.module.ts b/alcs-frontend/src/app/features/inquiry/inquiry.module.ts index 1f6340c586..5d58217b8f 100644 --- a/alcs-frontend/src/app/features/inquiry/inquiry.module.ts +++ b/alcs-frontend/src/app/features/inquiry/inquiry.module.ts @@ -5,7 +5,6 @@ import { RouterModule, Routes } from '@angular/router'; import { InquiryDetailService } from '../../services/inquiry/inquiry-detail.service'; import { SharedModule } from '../../shared/shared.module'; import { DetailsComponent } from './detail/details.component'; -import { DocumentUploadDialogComponent } from './documents/document-upload-dialog/document-upload-dialog.component'; import { DocumentsComponent } from './documents/documents.component'; import { HeaderComponent } from './header/header.component'; import { InquiryComponent, childRoutes } from './inquiry.component'; @@ -29,7 +28,6 @@ const routes: Routes = [ DetailsComponent, ParcelsComponent, DocumentsComponent, - DocumentUploadDialogComponent, ], imports: [CommonModule, SharedModule, RouterModule.forChild(routes), CdkDropList, CdkDrag], exports: [HeaderComponent], diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html index 2f8236b88e..4bfdf0d234 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html @@ -86,7 +86,7 @@

{{ title }} Document

-
+
Associated Parcel @@ -98,7 +98,7 @@

{{ title }} Document

-
+
Associated Organization From f0d61cb5a59b9ed009b413282108eeabd40e0c3a Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:27:59 -0800 Subject: [PATCH 13/30] Use shared upload dialog on notifications --- .../document-upload-dialog.component.html | 117 ---------- .../document-upload-dialog.component.scss | 88 -------- .../document-upload-dialog.component.spec.ts | 52 ----- .../document-upload-dialog.component.ts | 205 ------------------ .../documents/documents.component.ts | 4 +- .../notification/notification.module.ts | 2 - 6 files changed, 3 insertions(+), 465 deletions(-) delete mode 100644 alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.html delete mode 100644 alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.ts diff --git a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.html deleted file mode 100644 index 56e04b839c..0000000000 --- a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.html +++ /dev/null @@ -1,117 +0,0 @@ -
-

{{ title }} Document

-
-
-
-
-
- Document Upload* -
- -
- -
or drag and drop them here
- -
-
-
- {{ pendingFile.name }} -  ({{ pendingFile.size | filesize }}) -
- -
-
-
- {{ existingFile.name }} -  ({{ existingFile.size | filesize }}) -
- -
- - warning A virus was detected in the file. Choose another file and try again. - -
- -
- - Document Name - - {{ extension }} - -
- -
- - -
-
- - Source - - {{ source }} - - -
-
- Visible To: -
- Applicant, L/FNG -
-
- Public -
-
-
- - -
- - - -
-
-
diff --git a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.scss b/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.scss deleted file mode 100644 index ba93743c38..0000000000 --- a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.scss +++ /dev/null @@ -1,88 +0,0 @@ -@use '../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.superseded-warning { - background-color: colors.$secondary-color-dark; - color: #fff; - padding: 0 4px; -} - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} \ No newline at end of file diff --git a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.spec.ts deleted file mode 100644 index 1ccefa2049..0000000000 --- a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { NoiDocumentService } from '../../../../services/notice-of-intent/noi-document/noi-document.service'; -import { NoticeOfIntentParcelService } from '../../../../services/notice-of-intent/notice-of-intent-parcel/notice-of-intent-parcel.service'; -import { NoticeOfIntentSubmissionService } from '../../../../services/notice-of-intent/notice-of-intent-submission/notice-of-intent-submission.service'; -import { NotificationDocumentService } from '../../../../services/notification/notification-document/notification-document.service'; -import { ToastService } from '../../../../services/toast/toast.service'; - -import { DocumentUploadDialogComponent } from './document-upload-dialog.component'; - -describe('DocumentUploadDialogComponent', () => { - let component: DocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockNotificationDocumentService: DeepMocked; - - beforeEach(async () => { - mockNotificationDocumentService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DocumentUploadDialogComponent], - providers: [ - { - provide: NotificationDocumentService, - useValue: mockNotificationDocumentService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.ts deleted file mode 100644 index 0118619579..0000000000 --- a/alcs-frontend/src/app/features/notification/documents/document-upload-dialog/document-upload-dialog.component.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Subject } from 'rxjs'; -import { UpdateNoticeOfIntentDocumentDto } from '../../../../services/notice-of-intent/noi-document/noi-document.dto'; -import { NotificationDocumentDto } from '../../../../services/notification/notification-document/notification-document.dto'; -import { NotificationDocumentService } from '../../../../services/notification/notification-document/notification-document.service'; -import { ToastService } from '../../../../services/toast/toast.service'; -import { - DOCUMENT_SOURCE, - DOCUMENT_SYSTEM, - DOCUMENT_TYPE, - DocumentTypeDto, -} from '../../../../shared/document/document.dto'; -import { splitExtension } from '../../../../shared/utils/file'; -import { FileHandle } from '../../../../shared/drag-drop-file/drag-drop-file.directive'; - -@Component({ - selector: 'app-document-upload-dialog', - templateUrl: './document-upload-dialog.component.html', - styleUrls: ['./document-upload-dialog.component.scss'], -}) -export class DocumentUploadDialogComponent implements OnInit, OnDestroy { - $destroy = new Subject(); - DOCUMENT_TYPE = DOCUMENT_TYPE; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - title = 'Create'; - isDirty = false; - isSaving = false; - allowsFileEdit = true; - documentTypeAhead: string | undefined = undefined; - - name = new FormControl('', [Validators.required]); - type = new FormControl(undefined, [Validators.required]); - source = new FormControl('', [Validators.required]); - - visibleToInternal = new FormControl(false, [Validators.required]); - visibleToPublic = new FormControl(false, [Validators.required]); - - documentTypes: DocumentTypeDto[] = []; - documentSources = Object.values(DOCUMENT_SOURCE); - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - visibleToInternal: this.visibleToInternal, - visibleToPublic: this.visibleToPublic, - }); - - pendingFile: File | undefined; - existingFile: { name: string; size: number } | undefined; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; existingDocument?: NotificationDocumentDto }, - protected dialog: MatDialogRef, - private notificationDocumentService: NotificationDocumentService, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - this.loadDocumentTypes(); - - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - this.allowsFileEdit = document.system === DOCUMENT_SYSTEM.ALCS; - - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - this.form.patchValue({ - name: fileName, - type: document.type?.code, - source: document.source, - visibleToInternal: document.visibilityFlags.includes('A'), - visibleToPublic: document.visibilityFlags.includes('P'), - }); - this.documentTypeAhead = document.type!.code; - this.existingFile = { - name: document.fileName, - size: 0, - }; - } - } - - async onSubmit() { - const visibilityFlags: ('A' | 'G' | 'P')[] = []; - - if (this.visibleToInternal.getRawValue()) { - visibilityFlags.push('A'); - visibilityFlags.push('G'); - } - - if (this.visibleToPublic.getRawValue()) { - visibilityFlags.push('P'); - } - - const file = this.pendingFile; - const dto: UpdateNoticeOfIntentDocumentDto = { - fileName: this.name.value! + this.extension, - source: this.source.value as DOCUMENT_SOURCE, - typeCode: this.type.value as DOCUMENT_TYPE, - visibilityFlags, - file, - }; - - this.isSaving = true; - if (this.data.existingDocument) { - await this.notificationDocumentService.update(this.data.existingDocument.uuid, dto); - } else if (file !== undefined) { - try { - await this.notificationDocumentService.upload(this.data.fileId, { - ...dto, - file, - }); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - } - this.dialog.close(true); - this.isSaving = false; - } - - ngOnDestroy(): void { - this.$destroy.next(); - this.$destroy.complete(); - } - - filterDocumentTypes(term: string, item: DocumentTypeDto) { - const termLower = term.toLocaleLowerCase(); - return ( - item.label.toLocaleLowerCase().indexOf(termLower) > -1 || - item.oatsCode.toLocaleLowerCase().indexOf(termLower) > -1 - ); - } - - async onDocTypeSelected($event?: DocumentTypeDto) { - if ($event) { - this.type.setValue($event.code); - } else { - this.type.setValue(undefined); - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - const { fileName, extension } = splitExtension(selectedFiles[0].name); - this.pendingFile = selectedFiles[0]; - this.name.setValue(fileName); - this.extension = extension; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.notificationDocumentService.download( - this.data.existingDocument.uuid, - this.data.existingDocument.fileName, - ); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } - - private async loadDocumentTypes() { - const docTypes = await this.notificationDocumentService.fetchTypes(); - docTypes.sort((a, b) => (a.label > b.label ? 1 : -1)); - this.documentTypes = docTypes.filter((type) => type.code !== DOCUMENT_TYPE.ORIGINAL_APPLICATION); - } -} diff --git a/alcs-frontend/src/app/features/notification/documents/documents.component.ts b/alcs-frontend/src/app/features/notification/documents/documents.component.ts index bb416cf00e..354dc12198 100644 --- a/alcs-frontend/src/app/features/notification/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/notification/documents/documents.component.ts @@ -10,8 +10,8 @@ import { NotificationDocumentService } from '../../../services/notification/noti import { ToastService } from '../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../shared/confirmation-dialog/confirmation-dialog.service'; import { DOCUMENT_SYSTEM } from '../../../shared/document/document.dto'; -import { DocumentUploadDialogComponent } from './document-upload-dialog/document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../shared/constants'; +import { DocumentUploadDialogComponent } from '../../../shared/document-upload-dialog/document-upload-dialog.component'; @Component({ selector: 'app-notification-documents', @@ -55,6 +55,7 @@ export class NotificationDocumentsComponent implements OnInit { width: '70%', data: { fileId: this.fileId, + documentService: this.notificationDocumentService, }, }) .beforeClosed() @@ -96,6 +97,7 @@ export class NotificationDocumentsComponent implements OnInit { data: { fileId: this.fileId, existingDocument: element, + documentService: this.notificationDocumentService, }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/notification/notification.module.ts b/alcs-frontend/src/app/features/notification/notification.module.ts index ad79308bbe..f1435650d1 100644 --- a/alcs-frontend/src/app/features/notification/notification.module.ts +++ b/alcs-frontend/src/app/features/notification/notification.module.ts @@ -4,7 +4,6 @@ import { NotificationDetailService } from '../../services/notification/notificat import { SharedModule } from '../../shared/shared.module'; import { ApplicantInfoComponent } from './applicant-info/applicant-info.component'; import { NotificationDetailsModule } from './applicant-info/notification-details/notification-details.module'; -import { DocumentUploadDialogComponent } from './documents/document-upload-dialog/document-upload-dialog.component'; import { NotificationDocumentsComponent } from './documents/documents.component'; import { IntakeComponent } from './intake/intake.component'; import { NotificationComponent, postSubmissionRoutes } from './notification.component'; @@ -25,7 +24,6 @@ const routes: Routes = [ NotificationComponent, OverviewComponent, NotificationDocumentsComponent, - DocumentUploadDialogComponent, ApplicantInfoComponent, UncancelNotificationDialogComponent, IntakeComponent, From 9c39dbe9d476fa639792715411817df82ff55813 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:08:21 -0800 Subject: [PATCH 14/30] Switch PR's to use shared upload dialog --- .../document-upload-dialog.component.html | 114 ---------- .../document-upload-dialog.component.scss | 88 -------- .../document-upload-dialog.component.spec.ts | 49 ----- .../document-upload-dialog.component.ts | 194 ------------------ .../documents/documents.component.ts | 4 +- .../planning-review/planning-review.module.ts | 2 - 6 files changed, 3 insertions(+), 448 deletions(-) delete mode 100644 alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.html delete mode 100644 alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.ts diff --git a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.html deleted file mode 100644 index e1e82bbaa9..0000000000 --- a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.html +++ /dev/null @@ -1,114 +0,0 @@ -
-

{{ title }} Document

-
-
-
-
-
- Document Upload* -
- -
- -
or drag and drop them here
- -
-
-
- {{ pendingFile.name }} -  ({{ pendingFile.size | filesize }}) -
- -
-
-
- {{ existingFile.name }} -  ({{ existingFile.size | filesize }}) -
- -
- - warning A virus was detected in the file. Choose another file and try again. - -
- -
- - Document Name - - {{ extension }} - -
- -
- - -
-
- - Source - - {{ source }} - - -
-
- Visible To: -
- Commissioner -
-
-
- - -
- - - -
-
-
diff --git a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.scss b/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.scss deleted file mode 100644 index 312d8fadba..0000000000 --- a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.scss +++ /dev/null @@ -1,88 +0,0 @@ -@use '../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.superseded-warning { - background-color: colors.$secondary-color-dark; - color: #fff; - padding: 0 4px; -} - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} diff --git a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.spec.ts deleted file mode 100644 index 614aa11ccc..0000000000 --- a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { PlanningReviewDocumentService } from '../../../../services/planning-review/planning-review-document/planning-review-document.service'; -import { ToastService } from '../../../../services/toast/toast.service'; - -import { DocumentUploadDialogComponent } from './document-upload-dialog.component'; - -describe('DocumentUploadDialogComponent', () => { - let component: DocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockAppDocService: DeepMocked; - - beforeEach(async () => { - mockAppDocService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DocumentUploadDialogComponent], - providers: [ - { - provide: PlanningReviewDocumentService, - useValue: mockAppDocService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.ts deleted file mode 100644 index 705de633f9..0000000000 --- a/alcs-frontend/src/app/features/planning-review/documents/document-upload-dialog/document-upload-dialog.component.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Subject } from 'rxjs'; -import { - PlanningReviewDocumentDto, - UpdateDocumentDto, -} from '../../../../services/planning-review/planning-review-document/planning-review-document.dto'; -import { PlanningReviewDocumentService } from '../../../../services/planning-review/planning-review-document/planning-review-document.service'; -import { ToastService } from '../../../../services/toast/toast.service'; -import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from '../../../../shared/document/document.dto'; -import { FileHandle } from '../../../../shared/drag-drop-file/drag-drop-file.directive'; -import { splitExtension } from '../../../../shared/utils/file'; - -@Component({ - selector: 'app-document-upload-dialog', - templateUrl: './document-upload-dialog.component.html', - styleUrls: ['./document-upload-dialog.component.scss'], -}) -export class DocumentUploadDialogComponent implements OnInit, OnDestroy { - $destroy = new Subject(); - DOCUMENT_TYPE = DOCUMENT_TYPE; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - title = 'Create'; - isDirty = false; - isSaving = false; - documentTypeAhead: string | undefined = undefined; - - name = new FormControl('', [Validators.required]); - type = new FormControl(undefined, [Validators.required]); - source = new FormControl('', [Validators.required]); - visibleToCommissioner = new FormControl(false, [Validators.required]); - - documentTypes: DocumentTypeDto[] = []; - documentSources = Object.values(DOCUMENT_SOURCE); - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - visibleToCommissioner: this.visibleToCommissioner, - }); - - pendingFile: File | undefined; - existingFile: { name: string; size: number } | undefined; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; existingDocument?: PlanningReviewDocumentDto }, - protected dialog: MatDialogRef, - private planningReviewDocumentService: PlanningReviewDocumentService, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - this.loadDocumentTypes(); - - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - - this.form.patchValue({ - name: fileName, - type: document.type?.code, - source: document.source, - visibleToCommissioner: document.visibilityFlags.includes('C'), - }); - this.documentTypeAhead = document.type!.code; - this.existingFile = { - name: document.fileName, - size: 0, - }; - } - } - - async onSubmit() { - const visibilityFlags: 'C'[] = []; - - if (this.visibleToCommissioner.getRawValue()) { - visibilityFlags.push('C'); - } - - const file = this.pendingFile; - const dto: UpdateDocumentDto = { - fileName: this.name.value! + this.extension, - source: this.source.value as DOCUMENT_SOURCE, - typeCode: this.type.value as DOCUMENT_TYPE, - visibilityFlags, - file, - }; - - this.isSaving = true; - if (this.data.existingDocument) { - await this.planningReviewDocumentService.update(this.data.existingDocument.uuid, dto); - } else if (file !== undefined) { - try { - await this.planningReviewDocumentService.upload(this.data.fileId, { - ...dto, - file, - }); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - this.showVirusError = false; - } - - this.dialog.close(true); - this.isSaving = false; - } - - ngOnDestroy(): void { - this.$destroy.next(); - this.$destroy.complete(); - } - - filterDocumentTypes(term: string, item: DocumentTypeDto) { - const termLower = term.toLocaleLowerCase(); - return ( - item.label.toLocaleLowerCase().indexOf(termLower) > -1 || - item.oatsCode.toLocaleLowerCase().indexOf(termLower) > -1 - ); - } - - async onDocTypeSelected($event?: DocumentTypeDto) { - if ($event) { - this.type.setValue($event.code); - } else { - this.type.setValue(undefined); - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - this.pendingFile = selectedFiles[0]; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.planningReviewDocumentService.download( - this.data.existingDocument.uuid, - this.data.existingDocument.fileName, - ); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } - - private async loadDocumentTypes() { - const docTypes = await this.planningReviewDocumentService.fetchTypes(); - docTypes.sort((a, b) => (a.label > b.label ? 1 : -1)); - this.documentTypes = docTypes.filter((type) => type.code !== DOCUMENT_TYPE.ORIGINAL_APPLICATION); - } -} diff --git a/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts b/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts index aaa52334bf..ca8d11f53a 100644 --- a/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts @@ -8,8 +8,8 @@ import { PlanningReviewDocumentService } from '../../../services/planning-review import { ToastService } from '../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../shared/confirmation-dialog/confirmation-dialog.service'; import { DOCUMENT_SYSTEM } from '../../../shared/document/document.dto'; -import { DocumentUploadDialogComponent } from './document-upload-dialog/document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../shared/constants'; +import { DocumentUploadDialogComponent } from '../../../shared/document-upload-dialog/document-upload-dialog.component'; @Component({ selector: 'app-documents', @@ -55,6 +55,7 @@ export class DocumentsComponent implements OnInit { width: '70%', data: { fileId: this.fileId, + documentService: this.planningReviewDocumentService, }, }) .beforeClosed() @@ -96,6 +97,7 @@ export class DocumentsComponent implements OnInit { data: { fileId: this.fileId, existingDocument: element, + documentService: this.planningReviewDocumentService, }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/planning-review/planning-review.module.ts b/alcs-frontend/src/app/features/planning-review/planning-review.module.ts index 8cfc1b0c47..894135131c 100644 --- a/alcs-frontend/src/app/features/planning-review/planning-review.module.ts +++ b/alcs-frontend/src/app/features/planning-review/planning-review.module.ts @@ -4,7 +4,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PlanningReviewDetailService } from '../../services/planning-review/planning-review-detail.service'; import { SharedModule } from '../../shared/shared.module'; -import { DocumentUploadDialogComponent } from './documents/document-upload-dialog/document-upload-dialog.component'; import { DocumentsComponent } from './documents/documents.component'; import { HeaderComponent } from './header/header.component'; import { OverviewComponent } from './overview/overview.component'; @@ -31,7 +30,6 @@ const routes: Routes = [ OverviewComponent, HeaderComponent, DocumentsComponent, - DocumentUploadDialogComponent, ReferralComponent, CreatePlanningReferralDialogComponent, EvidentiaryRecordComponent, From 85a9acc84d28ff38d6ddc1b0e7dd79f81b69a827 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:37:59 -0800 Subject: [PATCH 15/30] Switch to shared upload dialog for NOI's --- .../document-upload-dialog.component.html | 142 --------- .../document-upload-dialog.component.scss | 88 ------ .../document-upload-dialog.component.spec.ts | 61 ---- .../document-upload-dialog.component.ts | 291 ------------------ .../documents/documents.component.ts | 30 +- .../notice-of-intent.module.ts | 2 - 6 files changed, 28 insertions(+), 586 deletions(-) delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.html delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.scss delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.spec.ts delete mode 100644 alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.ts diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.html deleted file mode 100644 index 25a0845a98..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.html +++ /dev/null @@ -1,142 +0,0 @@ -
-

{{ title }} Document

- Superseded - Not associated with Applicant Submission in Portal -
-
-
-
-
- Document Upload* -
- -
- -
or drag and drop them here
- -
-
-
- {{ pendingFile.name }} -  ({{ pendingFile.size | filesize }}) -
- -
-
-
- {{ existingFile.name }} -  ({{ existingFile.size | filesize }}) -
- -
- - warning A virus was detected in the file. Choose another file and try again. - -
- -
- - Document Name - - {{ this.extension }} - -
- -
- - -
-
- - Source - - {{ source }} - - -
-
- - Associated Parcel - - - #{{ parcel.index + 1 }} PID: - {{ parcel.pid | mask: '000-000-000' }} - No Data - - -
-
- - Associated Organization - - - {{ owner.label }} - - - -
-
- Visible To: -
- Applicant, L/FNG -
-
- Public -
-
-
- - -
- - - -
-
-
diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.scss b/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.scss deleted file mode 100644 index ba93743c38..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.scss +++ /dev/null @@ -1,88 +0,0 @@ -@use '../../../../../styles/colors'; - -.form { - display: grid; - grid-template-columns: 1fr 1fr; - row-gap: 32px; - column-gap: 32px; - - .double { - grid-column: 1/3; - } -} - -.full-width { - width: 100%; -} - -a { - word-break: break-all; -} - -.file { - border: 1px solid #000; - border-radius: 8px; - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; -} - -.upload-button { - margin-top: 6px !important; - - &.error { - border: 2px solid colors.$error-color; - } -} - -.spinner { - display: inline-block; - margin-right: 4px; -} - -:host::ng-deep { - .mdc-button__label { - display: flex; - align-items: center; - } -} - -.superseded-warning { - background-color: colors.$secondary-color-dark; - color: #fff; - padding: 0 4px; -} - -.file-drag-drop { - background: colors.$white; - border-radius: 4px; - - &:hover { - background: colors.$grey-light !important; - } - - button:nth-child(1) { - width: 100%; - background: colors.$white; - padding: 24px; - border: none; - - &:hover { - background: colors.$grey-light !important; - } - } - - .drag-text { - margin-top: 14px; - color: colors.$grey; - } - - .icon { - color: colors.$grey; - font-size: 36px; - height: 36px; - align-content: center; - margin-bottom: 4px; - } -} \ No newline at end of file diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.spec.ts deleted file mode 100644 index 113f491adb..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { NoiDocumentService } from '../../../../services/notice-of-intent/noi-document/noi-document.service'; -import { NoticeOfIntentParcelService } from '../../../../services/notice-of-intent/notice-of-intent-parcel/notice-of-intent-parcel.service'; -import { NoticeOfIntentSubmissionService } from '../../../../services/notice-of-intent/notice-of-intent-submission/notice-of-intent-submission.service'; -import { ToastService } from '../../../../services/toast/toast.service'; - -import { DocumentUploadDialogComponent } from './document-upload-dialog.component'; - -describe('DocumentUploadDialogComponent', () => { - let component: DocumentUploadDialogComponent; - let fixture: ComponentFixture; - - let mockNoiDocService: DeepMocked; - let mockParcelService: DeepMocked; - let mockSubmissionService: DeepMocked; - - beforeEach(async () => { - mockNoiDocService = createMock(); - - const mockDialogRef = { - close: jest.fn(), - afterClosed: jest.fn(), - subscribe: jest.fn(), - backdropClick: () => new EventEmitter(), - }; - - await TestBed.configureTestingModule({ - declarations: [DocumentUploadDialogComponent], - providers: [ - { - provide: NoiDocumentService, - useValue: mockNoiDocService, - }, - { - provide: NoticeOfIntentParcelService, - useValue: mockParcelService, - }, - { - provide: NoticeOfIntentSubmissionService, - useValue: mockSubmissionService, - }, - { provide: MatDialogRef, useValue: mockDialogRef }, - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: ToastService, useValue: {} }, - ], - imports: [MatDialogModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - - fixture = TestBed.createComponent(DocumentUploadDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.ts deleted file mode 100644 index 2f4a9ff3a1..0000000000 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/document-upload-dialog/document-upload-dialog.component.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Subject } from 'rxjs'; -import { - NoticeOfIntentDocumentDto, - UpdateNoticeOfIntentDocumentDto, -} from '../../../../services/notice-of-intent/noi-document/noi-document.dto'; -import { NoiDocumentService } from '../../../../services/notice-of-intent/noi-document/noi-document.service'; -import { NoticeOfIntentParcelService } from '../../../../services/notice-of-intent/notice-of-intent-parcel/notice-of-intent-parcel.service'; -import { NoticeOfIntentSubmissionService } from '../../../../services/notice-of-intent/notice-of-intent-submission/notice-of-intent-submission.service'; -import { ToastService } from '../../../../services/toast/toast.service'; -import { - DOCUMENT_SOURCE, - DOCUMENT_SYSTEM, - DOCUMENT_TYPE, - DocumentTypeDto, -} from '../../../../shared/document/document.dto'; -import { FileHandle } from '../../../../shared/drag-drop-file/drag-drop-file.directive'; -import { splitExtension } from '../../../../shared/utils/file'; - -@Component({ - selector: 'app-document-upload-dialog', - templateUrl: './document-upload-dialog.component.html', - styleUrls: ['./document-upload-dialog.component.scss'], -}) -export class DocumentUploadDialogComponent implements OnInit, OnDestroy { - $destroy = new Subject(); - DOCUMENT_TYPE = DOCUMENT_TYPE; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - title = 'Create'; - isDirty = false; - isSaving = false; - allowsFileEdit = true; - documentTypeAhead: string | undefined = undefined; - - name = new FormControl('', [Validators.required]); - type = new FormControl(undefined, [Validators.required]); - source = new FormControl('', [Validators.required]); - - parcelId = new FormControl(null); - ownerId = new FormControl(null); - - visibleToInternal = new FormControl(false, [Validators.required]); - visibleToPublic = new FormControl(false, [Validators.required]); - - documentTypes: DocumentTypeDto[] = []; - documentSources = Object.values(DOCUMENT_SOURCE); - selectableParcels: { uuid: string; index: number; pid?: string }[] = []; - selectableOwners: { uuid: string; label: string }[] = []; - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - visibleToInternal: this.visibleToInternal, - visibleToPublic: this.visibleToPublic, - parcelId: this.parcelId, - ownerId: this.ownerId, - }); - - pendingFile: File | undefined; - existingFile: { name: string; size: number } | undefined; - showSupersededWarning = false; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; existingDocument?: NoticeOfIntentDocumentDto }, - protected dialog: MatDialogRef, - private noiDocumentService: NoiDocumentService, - private noiSubmissionService: NoticeOfIntentSubmissionService, - private noiParcelService: NoticeOfIntentParcelService, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - this.loadDocumentTypes(); - - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - this.allowsFileEdit = document.system === DOCUMENT_SYSTEM.ALCS; - - if (document.type?.code === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { - this.prepareCertificateOfTitleUpload(document.uuid); - this.allowsFileEdit = false; - } - if (document.type?.code === DOCUMENT_TYPE.CORPORATE_SUMMARY) { - this.allowsFileEdit = false; - this.prepareCorporateSummaryUpload(document.uuid); - } - - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - this.form.patchValue({ - name: fileName, - type: document.type?.code, - source: document.source, - visibleToInternal: document.visibilityFlags.includes('A'), - visibleToPublic: document.visibilityFlags.includes('P'), - }); - this.documentTypeAhead = document.type!.code; - this.existingFile = { - name: document.fileName, - size: 0, - }; - } - } - - async onSubmit() { - const visibilityFlags: ('A' | 'G' | 'P')[] = []; - - if (this.visibleToInternal.getRawValue()) { - visibilityFlags.push('A'); - visibilityFlags.push('G'); - } - - if (this.visibleToPublic.getRawValue()) { - visibilityFlags.push('P'); - } - - const file = this.pendingFile; - const dto: UpdateNoticeOfIntentDocumentDto = { - fileName: this.name.value! + this.extension, - source: this.source.value as DOCUMENT_SOURCE, - typeCode: this.type.value as DOCUMENT_TYPE, - visibilityFlags, - parcelUuid: this.parcelId.value ?? undefined, - ownerUuid: this.ownerId.value ?? undefined, - file, - }; - - this.isSaving = true; - if (this.data.existingDocument) { - await this.noiDocumentService.update(this.data.existingDocument.uuid, dto); - } else if (file !== undefined) { - try { - await this.noiDocumentService.upload(this.data.fileId, { - ...dto, - file, - }); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - } - this.dialog.close(true); - this.isSaving = false; - } - - ngOnDestroy(): void { - this.$destroy.next(); - this.$destroy.complete(); - } - - filterDocumentTypes(term: string, item: DocumentTypeDto) { - const termLower = term.toLocaleLowerCase(); - return ( - item.label.toLocaleLowerCase().indexOf(termLower) > -1 || - item.oatsCode.toLocaleLowerCase().indexOf(termLower) > -1 - ); - } - - async onDocTypeSelected($event?: DocumentTypeDto) { - if ($event) { - this.type.setValue($event.code); - } else { - this.type.setValue(undefined); - } - - if (this.type.value === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { - await this.prepareCertificateOfTitleUpload(); - this.visibleToInternal.setValue(true); - } else { - this.parcelId.setValue(null); - this.parcelId.setValidators([]); - this.parcelId.updateValueAndValidity(); - } - - if (this.type.value === DOCUMENT_TYPE.CORPORATE_SUMMARY) { - await this.prepareCorporateSummaryUpload(); - this.visibleToInternal.setValue(true); - } else { - this.ownerId.setValue(null); - this.ownerId.setValidators([]); - this.ownerId.updateValueAndValidity(); - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - this.pendingFile = selectedFiles[0]; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.name.setValue(fileName); - this.extension = extension; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.noiDocumentService.download(this.data.existingDocument.uuid, this.data.existingDocument.fileName); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } - - private async prepareCertificateOfTitleUpload(uuid?: string) { - const parcels = await this.noiParcelService.fetchParcels(this.data.fileId); - if (parcels.length > 0) { - this.parcelId.setValidators([Validators.required]); - this.parcelId.updateValueAndValidity(); - this.source.setValue(DOCUMENT_SOURCE.APPLICANT); - - const selectedParcel = parcels.find((parcel) => parcel.certificateOfTitleUuid === uuid); - if (selectedParcel) { - this.parcelId.setValue(selectedParcel.uuid); - } else if (uuid) { - this.showSupersededWarning = true; - } - - this.selectableParcels = parcels.map((parcel, index) => ({ - uuid: parcel.uuid, - pid: parcel.pid, - index: index, - })); - } - } - - private async prepareCorporateSummaryUpload(uuid?: string) { - const submission = await this.noiSubmissionService.fetchSubmission(this.data.fileId); - if (submission.owners.length > 0) { - const owners = submission.owners; - this.ownerId.setValidators([Validators.required]); - this.ownerId.updateValueAndValidity(); - this.source.setValue(DOCUMENT_SOURCE.APPLICANT); - - const selectedOwner = owners.find((owner) => owner.corporateSummaryUuid === uuid); - if (selectedOwner) { - this.ownerId.setValue(selectedOwner.uuid); - } else if (uuid) { - this.showSupersededWarning = true; - } - - this.selectableOwners = owners - .filter((owner) => owner.type.code === 'ORGZ') - .map((owner, index) => ({ - label: owner.organizationName ?? owner.displayName, - uuid: owner.uuid, - })); - } - } - - private async loadDocumentTypes() { - const docTypes = await this.noiDocumentService.fetchTypes(); - docTypes.sort((a, b) => (a.label > b.label ? 1 : -1)); - this.documentTypes = docTypes.filter((type) => type.code !== DOCUMENT_TYPE.ORIGINAL_APPLICATION); - } -} diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts index beaef018cb..d5041c1313 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts @@ -16,8 +16,10 @@ import { NoiDocumentService } from '../../../services/notice-of-intent/noi-docum import { NoticeOfIntentDetailService } from '../../../services/notice-of-intent/notice-of-intent-detail.service'; import { ToastService } from '../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../shared/confirmation-dialog/confirmation-dialog.service'; -import { DocumentUploadDialogComponent } from './document-upload-dialog/document-upload-dialog.component'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../shared/constants'; +import { DocumentUploadDialogComponent } from '../../../shared/document-upload-dialog/document-upload-dialog.component'; +import { NoticeOfIntentSubmissionService } from '../../../services/notice-of-intent/notice-of-intent-submission/notice-of-intent-submission.service'; +import { NoticeOfIntentParcelService } from '../../../services/notice-of-intent/notice-of-intent-parcel/notice-of-intent-parcel.service'; @Component({ selector: 'app-noi-documents', @@ -43,7 +45,9 @@ export class NoiDocumentsComponent implements OnInit { private noiDocumentService: NoiDocumentService, private noticeOfIntentDetailService: NoticeOfIntentDetailService, private confirmationDialogService: ConfirmationDialogService, + private noiSubmissionService: NoticeOfIntentSubmissionService, private noiSubmissionStatusService: NoticeOfIntentSubmissionStatusService, + private noiParcelService: NoticeOfIntentParcelService, private toastService: ToastService, public dialog: MatDialog, ) {} @@ -60,6 +64,9 @@ export class NoiDocumentsComponent implements OnInit { } async onUploadFile() { + const submission = await this.noiSubmissionService.fetchSubmission(this.fileId); + const parcels = await this.noiParcelService.fetchParcels(this.fileId); + this.dialog .open(DocumentUploadDialogComponent, { minWidth: '600px', @@ -67,6 +74,14 @@ export class NoiDocumentsComponent implements OnInit { width: '70%', data: { fileId: this.fileId, + documentService: this.noiDocumentService, + selectableParcels: parcels.map((parcel, index) => ({ ...parcel, index })), + selectableOwners: submission.owners + .filter((owner) => owner.type.code === 'ORGZ') + .map((owner) => ({ + label: owner.organizationName ?? owner.displayName, + uuid: owner.uuid, + })), }, }) .beforeClosed() @@ -85,7 +100,10 @@ export class NoiDocumentsComponent implements OnInit { await this.noiDocumentService.download(uuid, fileName, false); } - onEditFile(element: NoticeOfIntentDocumentDto) { + async onEditFile(element: NoticeOfIntentDocumentDto) { + const submission = await this.noiSubmissionService.fetchSubmission(this.fileId); + const parcels = await this.noiParcelService.fetchParcels(this.fileId); + this.dialog .open(DocumentUploadDialogComponent, { minWidth: '600px', @@ -94,6 +112,14 @@ export class NoiDocumentsComponent implements OnInit { data: { fileId: this.fileId, existingDocument: element, + documentService: this.noiDocumentService, + selectableParcels: parcels.map((parcel, index) => ({ ...parcel, index })), + selectableOwners: submission.owners + .filter((owner) => owner.type.code === 'ORGZ') + .map((owner) => ({ + label: owner.organizationName ?? owner.displayName, + uuid: owner.uuid, + })), }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/notice-of-intent/notice-of-intent.module.ts b/alcs-frontend/src/app/features/notice-of-intent/notice-of-intent.module.ts index f1fe9e3613..40d7c57843 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/notice-of-intent.module.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/notice-of-intent.module.ts @@ -4,7 +4,6 @@ import { NoticeOfIntentDetailService } from '../../services/notice-of-intent/not import { SharedModule } from '../../shared/shared.module'; import { ApplicantInfoComponent } from './applicant-info/applicant-info.component'; import { NoticeOfIntentDetailsModule } from './applicant-info/notice-of-intent-details/notice-of-intent-details.module'; -import { DocumentUploadDialogComponent } from './documents/document-upload-dialog/document-upload-dialog.component'; import { NoiDocumentsComponent } from './documents/documents.component'; import { InfoRequestDialogComponent } from './info-requests/info-request-dialog/info-request-dialog.component'; import { InfoRequestsComponent } from './info-requests/info-requests.component'; @@ -41,7 +40,6 @@ const routes: Routes = [ PostDecisionComponent, EditModificationDialogComponent, NoiDocumentsComponent, - DocumentUploadDialogComponent, ApplicantInfoComponent, ProposalComponent, ParcelPrepComponent, From aefbeaa887de1077507f06bd8573864fa5f12a17 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:29:26 -0800 Subject: [PATCH 16/30] Handle scan fail error separately from infected error --- .../document-upload-dialog.component.html | 12 ++++++------ .../document-upload-dialog.component.ts | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html index 4bfdf0d234..c0bd9ec0e0 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html @@ -12,7 +12,7 @@

{{ title }} Document

*ngIf="!pendingFile && !existingFile" [ngClass]="{ 'file-drag-drop': true, - error: showVirusError, + error: showHasVirusError || showVirusScanFailedError, }" class="full-width upload-button" appDragDropFile @@ -47,9 +47,12 @@

{{ title }} Document

- + warning A virus was detected in the file. Choose another file and try again. + + warning There was a problem scanning the file for viruses. Please try again. +
@@ -73,11 +76,8 @@

{{ title }} Document

placeholder="Document Type*" > - - - warning A virus was detected in the file. Choose another file and try again. -
+
Source diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts index 7e9ef75b5d..437d231e20 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -58,7 +58,8 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { pendingFile: File | undefined; existingFile: { name: string; size: number } | undefined; showSupersededWarning = false; - showVirusError = false; + showHasVirusError = false; + showVirusScanFailedError = false; extension = ''; constructor( @@ -163,8 +164,12 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { } } catch (err) { this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; + if (err instanceof HttpErrorResponse) { + if (err.status === 400) { + this.showHasVirusError = true; + } else if (err.status === 500) { + this.showVirusScanFailedError = true; + } this.isSaving = false; this.pendingFile = undefined; return; @@ -256,7 +261,8 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { const { fileName, extension } = splitExtension(selectedFiles[0].name); this.name.setValue(fileName); this.extension = extension; - this.showVirusError = false; + this.showHasVirusError = false; + this.showVirusScanFailedError = false; } } @@ -298,7 +304,8 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { const { fileName, extension } = splitExtension(this.pendingFile.name); this.extension = extension; this.name.setValue(fileName); - this.showVirusError = false; + this.showHasVirusError = false; + this.showVirusScanFailedError = false; this.uploadFiles.emit($event); } From 044c42c52e152905ba31a094cbe6b0839152bc89 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:01:29 -0800 Subject: [PATCH 17/30] Make visibility flags configurable for shared upload dialogs --- .../decision-documents.component.ts | 1 + .../documents/documents.component.ts | 1 + .../decision-documents.component.ts | 1 + .../documents/documents.component.ts | 2 + .../documents/documents.component.ts | 2 + .../documents/documents.component.ts | 2 + .../document-upload-dialog.component.html | 14 +++-- .../document-upload-dialog.component.ts | 63 +++++++++++++++++-- .../document-upload-dialog.dto.ts | 2 +- 9 files changed, 78 insertions(+), 10 deletions(-) diff --git a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts index b7742657e0..7bd93f30be 100644 --- a/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts +++ b/alcs-frontend/src/app/features/application/decision/decision-v2/decision-documents/decision-documents.component.ts @@ -111,6 +111,7 @@ export class DecisionDocumentsComponent implements OnInit, OnDestroy { decisionUuid: this.decision?.uuid, existingDocument: existingDocument, decisionService: this.decisionService, + allowedVisibilityFlags: ['A', 'C', 'G', 'P'], }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/application/documents/documents.component.ts b/alcs-frontend/src/app/features/application/documents/documents.component.ts index f8200be725..0c4dc81e4c 100644 --- a/alcs-frontend/src/app/features/application/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/application/documents/documents.component.ts @@ -78,6 +78,7 @@ export class DocumentsComponent implements OnInit { label: owner.organizationName ?? owner.displayName, uuid: owner.uuid, })), + allowedVisibilityFlags: ['A', 'C', 'G', 'P'], }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts index fc0259e865..492e909828 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/decision/decision-v2/decision-documents/decision-documents.component.ts @@ -94,6 +94,7 @@ export class DecisionDocumentsComponent implements OnInit, OnDestroy { decisionUuid: this.decision?.uuid, existingDocument: existingDocument, decisionService: this.decisionService, + allowedVisibilityFlags: ['A', 'C', 'G', 'P'], }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts index d5041c1313..676c72faed 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts @@ -82,6 +82,7 @@ export class NoiDocumentsComponent implements OnInit { label: owner.organizationName ?? owner.displayName, uuid: owner.uuid, })), + allowedVisibilityFlags: ['A', 'C', 'G', 'P'], }, }) .beforeClosed() @@ -120,6 +121,7 @@ export class NoiDocumentsComponent implements OnInit { label: owner.organizationName ?? owner.displayName, uuid: owner.uuid, })), + allowedVisibilityFlags: ['A', 'C', 'G', 'P'], }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/notification/documents/documents.component.ts b/alcs-frontend/src/app/features/notification/documents/documents.component.ts index 354dc12198..570202de5e 100644 --- a/alcs-frontend/src/app/features/notification/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/notification/documents/documents.component.ts @@ -56,6 +56,7 @@ export class NotificationDocumentsComponent implements OnInit { data: { fileId: this.fileId, documentService: this.notificationDocumentService, + allowedVisibilityFlags: ['A', 'G', 'P'], }, }) .beforeClosed() @@ -98,6 +99,7 @@ export class NotificationDocumentsComponent implements OnInit { fileId: this.fileId, existingDocument: element, documentService: this.notificationDocumentService, + allowedVisibilityFlags: ['A', 'G', 'P'], }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts b/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts index ca8d11f53a..eb0e6e7337 100644 --- a/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/planning-review/documents/documents.component.ts @@ -56,6 +56,7 @@ export class DocumentsComponent implements OnInit { data: { fileId: this.fileId, documentService: this.planningReviewDocumentService, + allowedVisibilityFlags: ['C'], }, }) .beforeClosed() @@ -98,6 +99,7 @@ export class DocumentsComponent implements OnInit { fileId: this.fileId, existingDocument: element, documentService: this.planningReviewDocumentService, + allowedVisibilityFlags: ['C'], }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html index c0bd9ec0e0..0931a4cc91 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.html @@ -108,12 +108,18 @@

{{ title }} Document

-
+
Visible To: -
- Applicant, L/FNG, and Commissioner +
+ {{ internalVisibilityLabel }}
-
+
Public
diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts index 437d231e20..d2985696d5 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -62,6 +62,8 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { showVirusScanFailedError = false; extension = ''; + internalVisibilityLabel = ''; + constructor( @Inject(MAT_DIALOG_DATA) public data: { @@ -72,6 +74,7 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { documentService?: DocumentService; selectableParcels?: SelectableParcelDto[]; selectableOwners?: SelectableOwnerDto[]; + allowedVisibilityFlags?: ('A' | 'C' | 'G' | 'P')[]; }, protected dialog: MatDialogRef, private toastService: ToastService, @@ -80,6 +83,8 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { ngOnInit(): void { this.loadDocumentTypes(); + this.internalVisibilityLabel = this.buildInternalVisibilityLabel(); + if (this.data.existingDocument) { const document = this.data.existingDocument; this.title = 'Edit'; @@ -100,7 +105,10 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { this.form.patchValue({ name: fileName, source: document.source, - visibleToInternal: document.visibilityFlags?.includes('C') || document.visibilityFlags?.includes('A'), + visibleToInternal: + document.visibilityFlags?.includes('A') || + document.visibilityFlags?.includes('C') || + document.visibilityFlags?.includes('G'), visibleToPublic: document.visibilityFlags?.includes('P'), }); @@ -124,17 +132,62 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { } } + buildInternalVisibilityLabel(): string { + const ordinalsByWord = { + Applicant: 0, + 'L/FNG': 1, + Commissioner: 2, + }; + + type Word = keyof typeof ordinalsByWord; + + const wordsByFlag: { + A: Word; + G: Word; + C: Word; + } = { + A: 'Applicant', + G: 'L/FNG', + C: 'Commissioner', + }; + + const words = ( + this.data.allowedVisibilityFlags?.reduce((words, flag) => { + if (flag !== 'P') { + words.push(wordsByFlag[flag]); + } + return words; + }, [] as Word[]) ?? [] + ).sort((word1, word2) => ordinalsByWord[word1] - ordinalsByWord[word2]); + + if (words.length === 0) { + return ''; + } + + if (words.length === 1) { + return words[0]; + } + + if (words.length === 2) { + return `${words[0]} and ${words[1]}`; + } + + return `${words.slice(0, -1).join(', ')}, and ${words[words.length - 1]}`; + } + async onSubmit() { const file = this.pendingFile; const visibilityFlags: ('A' | 'C' | 'G' | 'P')[] = []; if (this.visibleToInternal.getRawValue()) { - visibilityFlags.push('A'); - visibilityFlags.push('G'); - visibilityFlags.push('C'); + for (const flag of this.data.allowedVisibilityFlags ?? []) { + if (flag !== 'P') { + visibilityFlags.push(flag); + } + } } - if (this.visibleToPublic.getRawValue()) { + if (this.visibleToPublic.getRawValue() && this.data.allowedVisibilityFlags?.includes('P')) { visibilityFlags.push('P'); } diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts index 20aee8bad8..73bb4085ff 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.dto.ts @@ -7,7 +7,7 @@ export interface UpdateDocumentDto { fileName: string; typeCode: DOCUMENT_TYPE; source: DOCUMENT_SOURCE; - visibilityFlags: ('A' | 'C' | 'G' | 'P')[]; + visibilityFlags?: ('A' | 'C' | 'G' | 'P')[]; } export interface CreateDocumentDto extends UpdateDocumentDto { From 9723c761e38522d6d63a368f3457e8e1375c5713 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:13:14 -0800 Subject: [PATCH 18/30] Allow configuring auto-visibility when selecting type --- .../documents/documents.component.ts | 15 +++++++++-- .../documents/documents.component.ts | 15 +++++++++-- .../document-upload-dialog.component.ts | 26 ++++++++++++++++--- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/alcs-frontend/src/app/features/application/documents/documents.component.ts b/alcs-frontend/src/app/features/application/documents/documents.component.ts index 0c4dc81e4c..14b01d9870 100644 --- a/alcs-frontend/src/app/features/application/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/application/documents/documents.component.ts @@ -5,7 +5,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { ApplicationSubmissionToSubmissionStatusDto } from '../../../services/application/application-submission-status/application-submission-status.dto'; import { ApplicationSubmissionStatusService } from '../../../services/application/application-submission-status/application-submission-status.service'; import { SUBMISSION_STATUS } from '../../../services/application/application.dto'; -import { DOCUMENT_SYSTEM } from '../../../shared/document/document.dto'; +import { DOCUMENT_SYSTEM, DOCUMENT_TYPE } from '../../../shared/document/document.dto'; import { ApplicationDetailService } from '../../../services/application/application-detail.service'; import { ApplicationDocumentDto } from '../../../services/application/application-document/application-document.dto'; import { ApplicationDocumentService } from '../../../services/application/application-document/application-document.service'; @@ -14,7 +14,10 @@ import { ConfirmationDialogService } from '../../../shared/confirmation-dialog/c import { FILE_NAME_TRUNCATE_LENGTH } from '../../../shared/constants'; import { ApplicationSubmissionService } from '../../../services/application/application-submission/application-submission.service'; import { ApplicationParcelService } from '../../../services/application/application-parcel/application-parcel.service'; -import { DocumentUploadDialogComponent } from '../../../shared/document-upload-dialog/document-upload-dialog.component'; +import { + DocumentUploadDialogComponent, + VisibilityGroup, +} from '../../../shared/document-upload-dialog/document-upload-dialog.component'; @Component({ selector: 'app-documents', @@ -79,6 +82,10 @@ export class DocumentsComponent implements OnInit { uuid: owner.uuid, })), allowedVisibilityFlags: ['A', 'C', 'G', 'P'], + documentTypeToVisibilityGroupsMap: { + [DOCUMENT_TYPE.CERTIFICATE_OF_TITLE]: [VisibilityGroup.INTERNAL], + [DOCUMENT_TYPE.CORPORATE_SUMMARY]: [VisibilityGroup.INTERNAL], + }, }, }) .beforeClosed() @@ -131,6 +138,10 @@ export class DocumentsComponent implements OnInit { label: owner.organizationName ?? owner.displayName, uuid: owner.uuid, })), + documentTypeToVisibilityGroupsMap: { + [DOCUMENT_TYPE.CERTIFICATE_OF_TITLE]: [VisibilityGroup.INTERNAL], + [DOCUMENT_TYPE.CORPORATE_SUMMARY]: [VisibilityGroup.INTERNAL], + }, }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts index 676c72faed..ff06f77ff8 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.ts @@ -9,7 +9,7 @@ import { NOI_SUBMISSION_STATUS, NoticeOfIntentSubmissionToSubmissionStatusDto, } from '../../../services/notice-of-intent/notice-of-intent.dto'; -import { DOCUMENT_SYSTEM } from '../../../shared/document/document.dto'; +import { DOCUMENT_SYSTEM, DOCUMENT_TYPE } from '../../../shared/document/document.dto'; import { ApplicationDocumentDto } from '../../../services/application/application-document/application-document.dto'; import { NoticeOfIntentDocumentDto } from '../../../services/notice-of-intent/noi-document/noi-document.dto'; import { NoiDocumentService } from '../../../services/notice-of-intent/noi-document/noi-document.service'; @@ -17,7 +17,10 @@ import { NoticeOfIntentDetailService } from '../../../services/notice-of-intent/ import { ToastService } from '../../../services/toast/toast.service'; import { ConfirmationDialogService } from '../../../shared/confirmation-dialog/confirmation-dialog.service'; import { FILE_NAME_TRUNCATE_LENGTH } from '../../../shared/constants'; -import { DocumentUploadDialogComponent } from '../../../shared/document-upload-dialog/document-upload-dialog.component'; +import { + DocumentUploadDialogComponent, + VisibilityGroup, +} from '../../../shared/document-upload-dialog/document-upload-dialog.component'; import { NoticeOfIntentSubmissionService } from '../../../services/notice-of-intent/notice-of-intent-submission/notice-of-intent-submission.service'; import { NoticeOfIntentParcelService } from '../../../services/notice-of-intent/notice-of-intent-parcel/notice-of-intent-parcel.service'; @@ -83,6 +86,10 @@ export class NoiDocumentsComponent implements OnInit { uuid: owner.uuid, })), allowedVisibilityFlags: ['A', 'C', 'G', 'P'], + documentTypeToVisibilityGroupsMap: { + [DOCUMENT_TYPE.CERTIFICATE_OF_TITLE]: [VisibilityGroup.INTERNAL], + [DOCUMENT_TYPE.CORPORATE_SUMMARY]: [VisibilityGroup.INTERNAL], + }, }, }) .beforeClosed() @@ -122,6 +129,10 @@ export class NoiDocumentsComponent implements OnInit { uuid: owner.uuid, })), allowedVisibilityFlags: ['A', 'C', 'G', 'P'], + documentTypeToVisibilityGroupsMap: { + [DOCUMENT_TYPE.CERTIFICATE_OF_TITLE]: [VisibilityGroup.INTERNAL], + [DOCUMENT_TYPE.CORPORATE_SUMMARY]: [VisibilityGroup.INTERNAL], + }, }, }) .beforeClosed() diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts index d2985696d5..41442c1319 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -16,6 +16,11 @@ import { } from './document-upload-dialog.dto'; import { Subject } from 'rxjs'; +export enum VisibilityGroup { + INTERNAL = 'Internal', + PUBLIC = 'Public', +} + @Component({ selector: 'app-document-upload-dialog', templateUrl: './document-upload-dialog.component.html', @@ -75,6 +80,7 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { selectableParcels?: SelectableParcelDto[]; selectableOwners?: SelectableOwnerDto[]; allowedVisibilityFlags?: ('A' | 'C' | 'G' | 'P')[]; + documentTypeToVisibilityGroupsMap: Record; }, protected dialog: MatDialogRef, private toastService: ToastService, @@ -279,18 +285,30 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { } async onDocTypeSelected($event?: DocumentTypeDto) { - if (this.type.value === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { + if (!$event) { + return; + } + + for (const visibilityGroup of this.data.documentTypeToVisibilityGroupsMap[$event.code]) { + if (visibilityGroup === VisibilityGroup.INTERNAL) { + this.visibleToInternal.setValue(true); + } + + if (visibilityGroup === VisibilityGroup.PUBLIC) { + this.visibleToPublic.setValue(true); + } + } + + if ($event.code === DOCUMENT_TYPE.CERTIFICATE_OF_TITLE) { await this.prepareCertificateOfTitleUpload(); - this.visibleToInternal.setValue(true); } else { this.parcelId.setValue(null); this.parcelId.setValidators([]); this.parcelId.updateValueAndValidity(); } - if (this.type.value === DOCUMENT_TYPE.CORPORATE_SUMMARY) { + if ($event.code === DOCUMENT_TYPE.CORPORATE_SUMMARY) { await this.prepareCorporateSummaryUpload(); - this.visibleToInternal.setValue(true); } else { this.ownerId.setValue(null); this.ownerId.setValidators([]); From 648f5e3c9ba1233d24cc7b350f2d29ff50ebe31a Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Thu, 9 Jan 2025 10:35:41 -0800 Subject: [PATCH 19/30] Update shared portal uploader to handle separate virus errors 1. Has virus 2. Virus scan failed --- .../file-drag-drop/file-drag-drop.component.html | 10 +++++++--- .../shared/file-drag-drop/file-drag-drop.component.ts | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html index 6a2efffad4..c5cd828a2e 100644 --- a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html +++ b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html @@ -4,7 +4,7 @@
{{ file.fileName }} @@ -27,8 +27,9 @@ *ngIf="!uploadedFiles.length || allowMultiple" [ngClass]="{ 'desktop-file-drag-drop': true, - 'error-outline': !disabled && ((isRequired && showErrors && !uploadedFiles.length) || showVirusError), - disabled: disabled + 'error-outline': + !disabled && ((isRequired && showErrors && !uploadedFiles.length) || showVirusError || showServerError), + disabled: disabled, }" dragDropFile (files)="filesDropped($event)" @@ -58,4 +59,7 @@ A virus was detected in the file. Choose another file and try again. + + There was a problem uploading the file. Please try again. + Maximum file size: 100 MB diff --git a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts index 0acc17688c..a7750e122b 100644 --- a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts +++ b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts @@ -20,6 +20,7 @@ export class FileDragDropComponent implements OnInit { @Input() isRequired = false; @Input() showErrors = false; @Input() showVirusError = false; + @Input() showServerError = false; private uploadClicked = false; From 3572c3878f464b374283beae5682d22d4b0e5d74 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:21:27 -0800 Subject: [PATCH 20/30] Add server error flag to all portal components with upload and pass into drag-n-drop component --- ...r-attachments-upload-dialog.component.html | 146 +++---- ...her-attachments-upload-dialog.component.ts | 380 ++++++++--------- .../parcel-entry/parcel-entry.component.html | 1 + .../parcel-entry/parcel-entry.component.ts | 1 + .../primary-contact.component.html | 1 + .../primary-contact.component.ts | 1 + .../cove-proposal.component.html | 2 + .../cove-proposal/cove-proposal.component.ts | 2 + .../excl-proposal.component.html | 4 + .../excl-proposal/excl-proposal.component.ts | 4 + .../incl-proposal.component.html | 4 + .../incl-proposal/incl-proposal.component.ts | 4 + .../naru-proposal.component.html | 2 + .../naru-proposal/naru-proposal.component.ts | 2 + .../nfu-proposal/nfu-proposal.component.html | 1 + .../nfu-proposal/nfu-proposal.component.ts | 1 + .../pfrs-proposal.component.html | 5 + .../pfrs-proposal/pfrs-proposal.component.ts | 5 + .../pofo-proposal.component.html | 4 + .../pofo-proposal/pofo-proposal.component.ts | 4 + .../roso-proposal.component.html | 4 + .../roso-proposal/roso-proposal.component.ts | 4 + .../subd-proposal.component.html | 2 + .../subd-proposal/subd-proposal.component.ts | 2 + .../tur-proposal/tur-proposal.component.html | 2 + .../tur-proposal/tur-proposal.component.ts | 2 + .../review-attachments.component.html | 3 + .../review-attachments.component.ts | 3 + .../additional-information.component.html | 1 + .../additional-information.component.ts | 1 + ...r-attachments-upload-dialog.component.html | 146 +++---- ...her-attachments-upload-dialog.component.ts | 375 ++++++++--------- .../parcel-entry/parcel-entry.component.html | 34 +- .../parcel-entry/parcel-entry.component.ts | 1 + .../primary-contact.component.html | 1 + .../primary-contact.component.ts | 1 + .../pfrs/pfrs-proposal.component.html | 4 + .../proposal/pfrs/pfrs-proposal.component.ts | 4 + .../pofo/pofo-proposal.component.html | 3 + .../proposal/pofo/pofo-proposal.component.ts | 3 + .../roso/roso-proposal.component.html | 4 + .../proposal/roso/roso-proposal.component.ts | 4 + ...r-attachments-upload-dialog.component.html | 150 +++---- ...her-attachments-upload-dialog.component.ts | 385 +++++++++--------- .../proposal/proposal.component.html | 2 + .../proposal/proposal.component.ts | 2 + .../owner-dialog/owner-dialog.component.html | 1 + .../owner-dialog/owner-dialog.component.ts | 1 + 48 files changed, 926 insertions(+), 793 deletions(-) diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 8622a33a24..7243a693d3 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -1,79 +1,79 @@
-

{{title}} optional attachment

+

{{ title }} optional attachment

-
- - -
-
-
-
- - - - {{ type.label }} - - - -
- warning -
- This field is required -
-
-
-
- - - -
- warning -
- This field is required -
-
-
+
+ + +
+ +
+
+ + + + {{ type.label }} + + + +
+ warning +
This field is required
+
+
+
+ + + +
+ warning +
This field is required
- +
+
+
-
- - - -
-
\ No newline at end of file +
+ + + +
+ diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index a84f186148..e401b8c361 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -1,212 +1,220 @@ -import { CommonModule } from "@angular/common"; +import { CommonModule } from '@angular/common'; import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; -import { ApplicationDocumentDto, ApplicationDocumentUpdateDto } from "../../../../../services/application-document/application-document.dto"; -import { ToastService } from "../../../../../services/toast/toast.service"; -import { ApplicationDocumentService } from "../../../../../services/application-document/application-document.service"; -import { FormControl, FormGroup, Validators } from "@angular/forms"; -import { OtherAttachmentsComponent } from "../other-attachments.component"; -import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from "../../../../../shared/dto/document.dto"; -import { CodeService } from "../../../../../services/code/code.service"; -import { FileHandle } from "../../../../../shared/file-drag-drop/drag-drop.directive"; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { + ApplicationDocumentDto, + ApplicationDocumentUpdateDto, +} from '../../../../../services/application-document/application-document.dto'; +import { ToastService } from '../../../../../services/toast/toast.service'; +import { ApplicationDocumentService } from '../../../../../services/application-document/application-document.service'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { OtherAttachmentsComponent } from '../other-attachments.component'; +import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from '../../../../../shared/dto/document.dto'; +import { CodeService } from '../../../../../services/code/code.service'; +import { FileHandle } from '../../../../../shared/file-drag-drop/drag-drop.directive'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @Component({ - selector: 'app-other-attachments-upload-dialog', - templateUrl: './other-attachments-upload-dialog.component.html', - styleUrl: './other-attachments-upload-dialog.component.scss', + selector: 'app-other-attachments-upload-dialog', + templateUrl: './other-attachments-upload-dialog.component.html', + styleUrl: './other-attachments-upload-dialog.component.scss', }) export class OtherAttachmentsUploadDialogComponent implements OnInit { - isDirty = false; - isFileDirty = false; - isSaving = false; - showVirusError = false; - showFileRequiredError = false; - title: string = ''; - isEditing = false; - - attachment: ApplicationDocumentDto[] = []; - attachmentForDelete: ApplicationDocumentDto[] = []; - pendingFile: FileHandle | undefined; - selectableTypes: DocumentTypeDto[] = []; - private documentCodes: DocumentTypeDto[] = []; - - fileDescription = new FormControl(null, [Validators.required]); - fileType = new FormControl(null, [Validators.required]); - currentDescription: string | null = null; - currentType: DocumentTypeDto | null = null; - - form = new FormGroup({ - fileDescription: this.fileDescription, - fileType: this.fileType, - }); - - constructor( - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) - public data: { - otherAttachmentsComponent: OtherAttachmentsComponent, - existingDocument?: ApplicationDocumentDto, - fileId: string, - }, - private applicationDcoumentService: ApplicationDocumentService, - private codeService: CodeService, - private toastService: ToastService - ) {} - - ngOnInit(): void { - this.loadDocumentCodes(); - if (this.data.existingDocument) { - this.title = 'Edit'; - this.isEditing = true; - this.fileType.setValue(this.data.existingDocument.type!.code); - this.fileDescription.setValue(this.data.existingDocument.description!); - this.currentDescription = this.data.existingDocument.description!; - this.currentType = this.data.existingDocument.type; - this.attachment = [this.data.existingDocument]; - } else { - this.title = 'Add'; - } + isDirty = false; + isFileDirty = false; + isSaving = false; + showVirusError = false; + showServerError = false; + showFileRequiredError = false; + title: string = ''; + isEditing = false; + + attachment: ApplicationDocumentDto[] = []; + attachmentForDelete: ApplicationDocumentDto[] = []; + pendingFile: FileHandle | undefined; + selectableTypes: DocumentTypeDto[] = []; + private documentCodes: DocumentTypeDto[] = []; + + fileDescription = new FormControl(null, [Validators.required]); + fileType = new FormControl(null, [Validators.required]); + currentDescription: string | null = null; + currentType: DocumentTypeDto | null = null; + + form = new FormGroup({ + fileDescription: this.fileDescription, + fileType: this.fileType, + }); + + constructor( + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) + public data: { + otherAttachmentsComponent: OtherAttachmentsComponent; + existingDocument?: ApplicationDocumentDto; + fileId: string; + }, + private applicationDcoumentService: ApplicationDocumentService, + private codeService: CodeService, + private toastService: ToastService, + ) {} + + ngOnInit(): void { + this.loadDocumentCodes(); + if (this.data.existingDocument) { + this.title = 'Edit'; + this.isEditing = true; + this.fileType.setValue(this.data.existingDocument.type!.code); + this.fileDescription.setValue(this.data.existingDocument.description!); + this.currentDescription = this.data.existingDocument.description!; + this.currentType = this.data.existingDocument.type; + this.attachment = [this.data.existingDocument]; + } else { + this.title = 'Add'; } - - async attachDocument(file: FileHandle) { - this.pendingFile = file; - this.attachment = [{uuid: '', - fileName: file.file.name, - type: null, - fileSize: file.file.size, - uploadedBy: '', - uploadedAt: file.file.lastModified, - source: DOCUMENT_SOURCE.APPLICANT, - }]; - this.isFileDirty = true; - this.showFileRequiredError = false; + } + + async attachDocument(file: FileHandle) { + this.pendingFile = file; + this.attachment = [ + { + uuid: '', + fileName: file.file.name, + type: null, + fileSize: file.file.size, + uploadedBy: '', + uploadedAt: file.file.lastModified, + source: DOCUMENT_SOURCE.APPLICANT, + }, + ]; + this.isFileDirty = true; + this.showFileRequiredError = false; + } + + openFile() { + if (this.isEditing && this.pendingFile === undefined) { + this.data.otherAttachmentsComponent.openFile(this.attachment[0]); + } else { + if (this.pendingFile) { + const fileURL = URL.createObjectURL(this.pendingFile.file); + window.open(fileURL, '_blank'); + } } + } - openFile() { - if (this.isEditing && this.pendingFile === undefined) { - this.data.otherAttachmentsComponent.openFile(this.attachment[0]); - } else { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile.file); - window.open(fileURL, '_blank'); - } - } + deleteFile() { + this.pendingFile = undefined; + if (this.isEditing) { + this.attachmentForDelete = this.attachment; } - - deleteFile() { - this.pendingFile = undefined; - if (this.isEditing) { - this.attachmentForDelete = this.attachment; - } - this.attachment = []; - } - - onChangeDescription() { - this.isDirty = true; - this.currentDescription = this.fileDescription.value; + this.attachment = []; + } + + onChangeDescription() { + this.isDirty = true; + this.currentDescription = this.fileDescription.value; + } + + onChangeType(selectedValue: DOCUMENT_TYPE) { + this.isDirty = true; + const newType = this.documentCodes.find((code) => code.code === selectedValue); + this.currentType = newType !== undefined ? newType : null; + } + + validateForm() { + if (this.form.valid && this.attachment.length !== 0) { + return true; } - onChangeType(selectedValue: DOCUMENT_TYPE) { - this.isDirty = true; - const newType = this.documentCodes.find((code) => code.code === selectedValue); - this.currentType = newType !== undefined ? newType : null; + if (this.form.invalid) { + this.form.markAllAsTouched(); } - validateForm() { - if (this.form.valid && this.attachment.length !== 0) { - return true; - } - - if (this.form.invalid) { - this.form.markAllAsTouched(); - } - - if (this.attachment.length == 0) { - this.showFileRequiredError = true; - } - return false; - } - - async onAdd() { - if (this.validateForm()) { - await this.add(); - } + if (this.attachment.length == 0) { + this.showFileRequiredError = true; } + return false; + } - protected async add() { - if (this.isFileDirty) { - this.isSaving = true; - const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); - this.showVirusError = !res; - if (res) { - const documents = await this.applicationDcoumentService.getByFileId(this.data.fileId); - if (documents) { - const sortedDocuments = documents.sort((a, b) => {return b.uploadedAt - a.uploadedAt}); - const updateDtos: ApplicationDocumentUpdateDto[] = sortedDocuments.map((file) => ({ - uuid: file.uuid, - description: file.description, - type: file.type?.code ?? null, - })); - updateDtos[0] = { - ...updateDtos[0], - description: this.currentDescription, - type: this.currentType?.code ?? null, - } - await this.applicationDcoumentService.update(this.data.fileId, updateDtos); - this.toastService.showSuccessToast('Attachment added successfully'); - this.dialogRef.close(); - } else { - this.toastService.showErrorToast("Could not read attached documents"); - } - } - } + async onAdd() { + if (this.validateForm()) { + await this.add(); } - - async onEdit() { - if (this.validateForm()) { - this.edit(); + } + + protected async add() { + if (this.isFileDirty) { + this.isSaving = true; + const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); + this.showVirusError = !res; + if (res) { + const documents = await this.applicationDcoumentService.getByFileId(this.data.fileId); + if (documents) { + const sortedDocuments = documents.sort((a, b) => { + return b.uploadedAt - a.uploadedAt; + }); + const updateDtos: ApplicationDocumentUpdateDto[] = sortedDocuments.map((file) => ({ + uuid: file.uuid, + description: file.description, + type: file.type?.code ?? null, + })); + updateDtos[0] = { + ...updateDtos[0], + description: this.currentDescription, + type: this.currentType?.code ?? null, + }; + await this.applicationDcoumentService.update(this.data.fileId, updateDtos); + this.toastService.showSuccessToast('Attachment added successfully'); + this.dialogRef.close(); + } else { + this.toastService.showErrorToast('Could not read attached documents'); } + } } + } - protected async edit() { - if (this.isFileDirty) { - this.data.otherAttachmentsComponent.onDeleteFile(this.attachmentForDelete[0]); - await this.add(); - } else { - if (this.isDirty) { - this.isSaving = true; - const documents = await this.applicationDcoumentService.getByFileId(this.data.fileId); - if (documents) { - const updateDtos: ApplicationDocumentUpdateDto[] = documents.map((file) => ({ - uuid: file.uuid, - description: file.description, - type: file.type?.code ?? null, - })); - for (let i = 0; i < updateDtos.length; i++) { - if (updateDtos[i].uuid === this.data.existingDocument?.uuid) { - updateDtos[i] = { - ...updateDtos[i], - description: this.currentDescription, - type: this.currentType?.code ?? null, - } - } - } - await this.applicationDcoumentService.update(this.data.fileId, updateDtos); - this.toastService.showSuccessToast('Attachment updated successully'); - } else { - this.toastService.showErrorToast("Could not read attached documents"); - } + async onEdit() { + if (this.validateForm()) { + this.edit(); + } + } + + protected async edit() { + if (this.isFileDirty) { + this.data.otherAttachmentsComponent.onDeleteFile(this.attachmentForDelete[0]); + await this.add(); + } else { + if (this.isDirty) { + this.isSaving = true; + const documents = await this.applicationDcoumentService.getByFileId(this.data.fileId); + if (documents) { + const updateDtos: ApplicationDocumentUpdateDto[] = documents.map((file) => ({ + uuid: file.uuid, + description: file.description, + type: file.type?.code ?? null, + })); + for (let i = 0; i < updateDtos.length; i++) { + if (updateDtos[i].uuid === this.data.existingDocument?.uuid) { + updateDtos[i] = { + ...updateDtos[i], + description: this.currentDescription, + type: this.currentType?.code ?? null, + }; } - this.dialogRef.close(); + } + await this.applicationDcoumentService.update(this.data.fileId, updateDtos); + this.toastService.showSuccessToast('Attachment updated successully'); + } else { + this.toastService.showErrorToast('Could not read attached documents'); } + } + this.dialogRef.close(); } + } - private async loadDocumentCodes() { - const codes = await this.codeService.loadCodes(); - this.documentCodes = codes.documentTypes; - this.selectableTypes = this.documentCodes.filter((code) => USER_CONTROLLED_TYPES.includes(code.code)); - } - + private async loadDocumentCodes() { + const codes = await this.codeService.loadCodes(); + this.documentCodes = codes.documentTypes; + this.selectableTypes = this.documentCodes.filter((code) => USER_CONTROLLED_TYPES.includes(code.code)); + } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html index 34240f1843..39fcef1a7d 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html @@ -242,6 +242,7 @@ [showErrors]="showErrors" [isRequired]="isCertificateOfTitleRequired" [showVirusError]="showVirusError" + [showServerError]="showServerError" [disabled]="parcelForm.controls.pid.disabled" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts index 617204efdf..1acb18112b 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts @@ -58,6 +58,7 @@ export class ParcelEntryComponent implements OnInit { @Input() isDraft = false; showVirusError = false; + showServerError = false; @Output() private onFormGroupChange = new EventEmitter>(); @Output() private onSaveProgress = new EventEmitter(); diff --git a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html index 50ab41d8fb..926ad3b58a 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html @@ -218,6 +218,7 @@

[showErrors]="showErrors" [isRequired]="needsAuthorizationLetter" [showVirusError]="showVirusError" + [showServerError]="showServerError" >

diff --git a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts index eb7c05bd35..2f951256be 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts @@ -44,6 +44,7 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni governmentName: string | undefined; isDirty = false; showVirusError = false; + showServerError = false; hasCrownParcels = false; ownersList = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html index 3a405b9f67..89df02f198 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html @@ -186,6 +186,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" >
@@ -230,6 +231,7 @@

Proposal

[isRequired]="true" [disabled]="!canUploadDraft" [showVirusError]="showDraftCovenantVirus" + [showServerError]="showDraftCovenantServerError" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts index 91ba649d56..ed02d2ef7e 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts @@ -50,8 +50,10 @@ export class CoveProposalComponent extends FilesStepComponent implements OnInit, proposalMap: ApplicationDocumentDto[] = []; showProposalMapVirus = false; + showProposalMapServerError = false; draftCovenant: ApplicationDocumentDto[] = []; showDraftCovenantVirus = false; + showDraftCovenantServerError = false; isMobile = false; visibleCount = VISIBLE_COUNT_INCREMENT; diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html index c9b3eae36c..263241b30c 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html @@ -135,6 +135,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" >
@@ -177,6 +178,7 @@

Notification and Public Hearing Requirements

[allowMultiple]="true" [isRequired]="true" [showVirusError]="showProofOfAdvertisingVirus" + [showServerError]="showProofOfAdvertisingServerError" >
@@ -195,6 +197,7 @@

Notification and Public Hearing Requirements

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showProofOfSignageVirus" + [showServerError]="showProofOfSignageServerError" >
@@ -210,6 +213,7 @@

Notification and Public Hearing Requirements

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showReportOfPublicHearingVirus" + [showServerError]="showReportOfPublicHearingServerError" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts index 4bf9578a1c..dbdb0f76e3 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts @@ -26,9 +26,13 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, prescribedBody: string | null = null; showProposalMapVirus = false; + showProposalMapServerError = false; showProofOfAdvertisingVirus = false; + showProofOfAdvertisingServerError = false; showProofOfSignageVirus = false; + showProofOfSignageServerError = false; showReportOfPublicHearingVirus = false; + showReportOfPublicHearingServerError = false; hectares = new FormControl(null, [Validators.required]); shareProperty = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html index fc4f8ff429..9b1bb4b82c 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html @@ -126,6 +126,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" >
@@ -215,6 +216,7 @@

Notification and Public Hearing Requirements

[disabled]="disableNotificationFileUploads" [allowMultiple]="true" [showVirusError]="showProofOfAdvertisingVirus" + [showServerError]="showProofOfAdvertisingServerError" >
@@ -234,6 +236,7 @@

Notification and Public Hearing Requirements

[disabled]="disableNotificationFileUploads" [allowMultiple]="true" [showVirusError]="showProofOfSignageVirus" + [showServerError]="showProofOfSignageServerError" >
@@ -249,6 +252,7 @@

Notification and Public Hearing Requirements

[isRequired]="!disableNotificationFileUploads" [disabled]="disableNotificationFileUploads" [showVirusError]="showReportOfPublicHearingVirus" + [showServerError]="showReportOfPublicHearingServerError" [allowMultiple]="true" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts index b292bcd70d..588bf5eaf6 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts @@ -38,9 +38,13 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, disableNotificationFileUploads = true; showProposalMapVirus = false; + showProposalMapServerError = false; showProofOfAdvertisingVirus = false; + showProofOfAdvertisingServerError = false; showProofOfSignageVirus = false; + showProofOfSignageServerError = false; showReportOfPublicHearingVirus = false; + showReportOfPublicHearingServerError = false; hectares = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html index fdad5b04ed..6a58a3ae21 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html @@ -643,6 +643,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" > @@ -660,6 +661,7 @@

Proposal

(openFile)="openFile($event)" [showErrors]="showErrors" [showVirusError]="showBuildingPlanVirus" + [showServerError]="showBuildingPlanServerError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts index 31dc7d862d..aef4cf2b7b 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts @@ -34,7 +34,9 @@ export class NaruProposalComponent extends FilesStepComponent implements OnInit, currentStep = EditApplicationSteps.Proposal; showProposalMapVirus = false; + showProposalMapServerError = false; showBuildingPlanVirus = false; + showBuildingPlanServerError = false; willBeOverFiveHundredM2 = new FormControl(null, [Validators.required]); willRetainResidence = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html index f21a41495c..f687836913 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html @@ -121,6 +121,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts index 09fd87a73c..6d940e560c 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts @@ -26,6 +26,7 @@ export class NfuProposalComponent extends FilesStepComponent implements OnInit, fillTableData: SoilTableData = {}; fillTableDisabled = true; showProposalMapVirus = false; + showProposalMapServerError = false; hectares = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html index a75d8cf34f..c9b32aca50 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html @@ -684,6 +684,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" >
@@ -710,6 +711,7 @@

Proposal

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showCrossSectionVirus" + [showServerError]="showCrossSectionServerError" > @@ -738,6 +740,7 @@

Proposal

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showReclamationPlanVirus" + [showServerError]="showReclamationPlanServerError" > @@ -757,6 +760,7 @@

Proposal

(openFile)="openFile($event)" [showErrors]="showErrors" [showVirusError]="showBuildingPlanVirus" + [showServerError]="showBuildingPlanServerError" [isRequired]="true" [allowMultiple]="true" > @@ -863,6 +867,7 @@

Proposal

[disabled]="!requiresNoticeOfWork" [allowMultiple]="true" [showVirusError]="showNoticeOfWorkVirus" + [showServerError]="showNoticeOfWorkServerError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts index e887069f3d..c3679a0d1e 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts @@ -55,10 +55,15 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, areComponentsDirty = false; showProposalMapVirus = false; + showProposalMapServerError = false; showCrossSectionVirus = false; + showCrossSectionServerError = false; showReclamationPlanVirus = false; + showReclamationPlanServerError = false; showBuildingPlanVirus = false; + showBuildingPlanServerError = false; showNoticeOfWorkVirus = false; + showNoticeOfWorkServerError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html index 80c3e64ae8..8ce0e4c2e9 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html @@ -594,6 +594,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" > @@ -620,6 +621,7 @@

Proposal

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showCrossSectionVirus" + [showServerError]="showCrossSectionServerError" > @@ -648,6 +650,7 @@

Proposal

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showReclamationPlanVirus" + [showServerError]="showReclamationPlanServerError" > @@ -667,6 +670,7 @@

Proposal

(openFile)="openFile($event)" [showErrors]="showErrors" [showVirusError]="showBuildingPlanVirus" + [showServerError]="showBuildingPlanServerError" [isRequired]="true" [allowMultiple]="true" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts index a9635c9777..68891874ab 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts @@ -54,9 +54,13 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, buildingPlans: ApplicationDocumentDto[] = []; showProposalMapVirus = false; + showProposalMapServerError = false; showCrossSectionVirus = false; + showCrossSectionServerError = false; showReclamationPlanVirus = false; + showReclamationPlanServerError = false; showBuildingPlanVirus = false; + showBuildingPlanServerError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html index 91f79ea8ae..24fcbed757 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html @@ -562,6 +562,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" > @@ -588,6 +589,7 @@

Proposal

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showCrossSectionVirus" + [showServerError]="showCrossSectionServerError" > @@ -616,6 +618,7 @@

Proposal

[isRequired]="true" [allowMultiple]="true" [showVirusError]="showReclamationPlanVirus" + [showServerError]="showReclamationPlanServerError" > @@ -635,6 +638,7 @@

Proposal

(openFile)="openFile($event)" [showErrors]="showErrors" [showVirusError]="showBuildingPlanVirus" + [showServerError]="showBuildingPlanServerError" [isRequired]="true" [allowMultiple]="true" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts index 3bea4eb978..ce52c4f405 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts @@ -54,9 +54,13 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, buildingPlans: ApplicationDocumentDto[] = []; showProposalMapVirus = false; + showProposalMapServerError = false; showCrossSectionVirus = false; + showCrossSectionServerError = false; showReclamationPlanVirus = false; + showReclamationPlanServerError = false; showBuildingPlanVirus = false; + showBuildingPlanServerError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html index 9029fd3495..345b1bfd60 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html @@ -216,6 +216,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" >
@@ -272,6 +273,7 @@

Proposal

[allowMultiple]="true" [disabled]="isHomeSiteSeverance.getRawValue() !== 'true'" [showVirusError]="showHomesiteSeveranceVirus" + [showServerError]="showHomesiteSeveranceServerError" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts index 8149f2a71a..2e2c973c73 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts @@ -32,7 +32,9 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit, proposalMap: ApplicationDocumentDto[] = []; showHomesiteSeveranceVirus = false; + showHomesiteSeveranceServerError = false; showProposalMapVirus = false; + showProposalMapServerError = false; lotsProposed = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html index 730f9cf721..aa95d2293b 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html @@ -179,6 +179,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showServingNoticeVirus" + [showServerError]="showServingNoticeServerError" data-testid="proof-of-serving-notice-filechooser" > @@ -194,6 +195,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" data-testid="proposal-map-filechooser" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts index adab6177fe..f373b58ccb 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts @@ -27,7 +27,9 @@ export class TurProposalComponent extends FilesStepComponent implements OnInit, proposalMap: ApplicationDocumentDto[] = []; showServingNoticeVirus = false; + showServingNoticeServerError = false; showProposalMapVirus = false; + showProposalMapServerError = false; purpose = new FormControl(null, [Validators.required]); outsideLands = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html index 945a20c66d..a97fe26d46 100644 --- a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html +++ b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html @@ -19,6 +19,7 @@

Attachments

[isRequired]="true" [showErrors]="showErrors" [showVirusError]="showResolutionVirusError" + [showServerError]="showResolutionServerError" >
@@ -32,6 +33,7 @@

Attachments

[isRequired]="isAuthorized" [showErrors]="showErrors" [showVirusError]="showStaffReportVirusError" + [showServerError]="showStaffReportServerError" >
@@ -44,6 +46,7 @@

Attachments

(openFile)="openFile($event)" [allowMultiple]="true" [showVirusError]="showOtherVirusError" + [showServerError]="showOtherServerError" >
diff --git a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts index f0156a2999..4fd6313af8 100644 --- a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts +++ b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts @@ -33,8 +33,11 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { showMandatoryUploads = false; hasCompletedPreviousSteps = false; showResolutionVirusError = false; + showResolutionServerError = false; showStaffReportVirusError = false; + showStaffReportServerError = false; showOtherVirusError = false; + showOtherServerError = false; constructor( private applicationReviewService: ApplicationSubmissionReviewService, diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html index a79f4e2a60..66badd1bee 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html @@ -382,6 +382,7 @@

Additional Proposal Information

(openFile)="openFile($event)" [showErrors]="showErrors" [showVirusError]="showBuildingPlanVirus" + [showServerError]="showBuildingPlanServerError" [isRequired]="confirmRemovalOfSoil" [allowMultiple]="true" [disabled]="!confirmRemovalOfSoil" diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts index cce35f4b30..9cb0d04970 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts @@ -96,6 +96,7 @@ export class AdditionalInformationComponent extends FilesStepComponent implement confirmRemovalOfSoil = false; showBuildingPlanVirus = false; + showBuildingPlanServerError = false; buildingPlans: NoticeOfIntentDocumentDto[] = []; proposedStructures: FormProposedStructure[] = []; diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 8622a33a24..7243a693d3 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -1,79 +1,79 @@
-

{{title}} optional attachment

+

{{ title }} optional attachment

-
- - -
-
-
-
- - - - {{ type.label }} - - - -
- warning -
- This field is required -
-
-
-
- - - -
- warning -
- This field is required -
-
-
+
+ + +
+ +
+
+ + + + {{ type.label }} + + + +
+ warning +
This field is required
+
+
+
+ + + +
+ warning +
This field is required
- +
+
+
-
- - - -
-
\ No newline at end of file +
+ + + +
+ diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index fc9d0fd864..d02391dfd1 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -1,210 +1,219 @@ import { Component, Inject, type OnInit } from '@angular/core'; -import { NoticeOfIntentDocumentDto, NoticeOfIntentDocumentUpdateDto } from "../../../../../services/notice-of-intent-document/notice-of-intent-document.dto"; -import { FileHandle } from "../../../../../shared/file-drag-drop/drag-drop.directive"; -import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from "../../../../../shared/dto/document.dto"; -import { FormControl, FormGroup, Validators } from "@angular/forms"; -import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; -import { OtherAttachmentsComponent } from "../other-attachments.component"; -import { NoticeOfIntentDocumentService } from "../../../../../services/notice-of-intent-document/notice-of-intent-document.service"; -import { CodeService } from "../../../../../services/code/code.service"; -import { ToastService } from "../../../../../services/toast/toast.service"; +import { + NoticeOfIntentDocumentDto, + NoticeOfIntentDocumentUpdateDto, +} from '../../../../../services/notice-of-intent-document/notice-of-intent-document.dto'; +import { FileHandle } from '../../../../../shared/file-drag-drop/drag-drop.directive'; +import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from '../../../../../shared/dto/document.dto'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { OtherAttachmentsComponent } from '../other-attachments.component'; +import { NoticeOfIntentDocumentService } from '../../../../../services/notice-of-intent-document/notice-of-intent-document.service'; +import { CodeService } from '../../../../../services/code/code.service'; +import { ToastService } from '../../../../../services/toast/toast.service'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @Component({ - selector: 'app-other-attachments-upload-dialog', - templateUrl: './other-attachments-upload-dialog.component.html', - styleUrl: './other-attachments-upload-dialog.component.scss', + selector: 'app-other-attachments-upload-dialog', + templateUrl: './other-attachments-upload-dialog.component.html', + styleUrl: './other-attachments-upload-dialog.component.scss', }) export class OtherAttachmentsUploadDialogComponent implements OnInit { - isDirty = false; - isFileDirty = false; - isSaving = false; - showVirusError = false; - showFileRequiredError = false; - title: string = ''; - isEditing = false; - - attachment: NoticeOfIntentDocumentDto[] = []; - attachmentForDelete: NoticeOfIntentDocumentDto[] = []; - pendingFile: FileHandle | undefined; - selectableTypes: DocumentTypeDto[] = []; - private documentCodes: DocumentTypeDto[] = []; - - fileDescription = new FormControl(null, [Validators.required]); - fileType = new FormControl(null, [Validators.required]); - currentDescription: string | null = null; - currentType: DocumentTypeDto | null = null; - - form = new FormGroup({ - fileDescription: this.fileDescription, - fileType: this.fileType, - }); - - constructor( - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) - public data: { - otherAttachmentsComponent: OtherAttachmentsComponent, - existingDocument?: NoticeOfIntentDocumentDto, - fileId: string, - }, - private noticeOfIntentDocumentService: NoticeOfIntentDocumentService, - private codeService: CodeService, - private toastService: ToastService - ) {} - - ngOnInit(): void { - this.loadDocumentCodes(); - if (this.data.existingDocument) { - this.title = 'Edit'; - this.isEditing = true; - this.fileType.setValue(this.data.existingDocument.type!.code); - this.fileDescription.setValue(this.data.existingDocument.description!); - this.currentDescription = this.data.existingDocument.description!; - this.currentType = this.data.existingDocument.type; - this.attachment = [this.data.existingDocument]; - } else { - this.title = 'Add'; - } - } - - async attachDocument(file: FileHandle) { - this.pendingFile = file; - this.attachment = [{uuid: '', - fileName: file.file.name, - type: null, - fileSize: file.file.size, - uploadedBy: '', - uploadedAt: file.file.lastModified, - source: DOCUMENT_SOURCE.APPLICANT, - }]; - this.isFileDirty = true; - this.showFileRequiredError = false; + isDirty = false; + isFileDirty = false; + isSaving = false; + showVirusError = false; + showServerError = false; + showFileRequiredError = false; + title: string = ''; + isEditing = false; + + attachment: NoticeOfIntentDocumentDto[] = []; + attachmentForDelete: NoticeOfIntentDocumentDto[] = []; + pendingFile: FileHandle | undefined; + selectableTypes: DocumentTypeDto[] = []; + private documentCodes: DocumentTypeDto[] = []; + + fileDescription = new FormControl(null, [Validators.required]); + fileType = new FormControl(null, [Validators.required]); + currentDescription: string | null = null; + currentType: DocumentTypeDto | null = null; + + form = new FormGroup({ + fileDescription: this.fileDescription, + fileType: this.fileType, + }); + + constructor( + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) + public data: { + otherAttachmentsComponent: OtherAttachmentsComponent; + existingDocument?: NoticeOfIntentDocumentDto; + fileId: string; + }, + private noticeOfIntentDocumentService: NoticeOfIntentDocumentService, + private codeService: CodeService, + private toastService: ToastService, + ) {} + + ngOnInit(): void { + this.loadDocumentCodes(); + if (this.data.existingDocument) { + this.title = 'Edit'; + this.isEditing = true; + this.fileType.setValue(this.data.existingDocument.type!.code); + this.fileDescription.setValue(this.data.existingDocument.description!); + this.currentDescription = this.data.existingDocument.description!; + this.currentType = this.data.existingDocument.type; + this.attachment = [this.data.existingDocument]; + } else { + this.title = 'Add'; } - - openFile() { - if (this.isEditing && this.pendingFile === undefined) { - this.data.otherAttachmentsComponent.openFile(this.attachment[0]); - } else { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile.file); - window.open(fileURL, '_blank'); - } - } + } + + async attachDocument(file: FileHandle) { + this.pendingFile = file; + this.attachment = [ + { + uuid: '', + fileName: file.file.name, + type: null, + fileSize: file.file.size, + uploadedBy: '', + uploadedAt: file.file.lastModified, + source: DOCUMENT_SOURCE.APPLICANT, + }, + ]; + this.isFileDirty = true; + this.showFileRequiredError = false; + } + + openFile() { + if (this.isEditing && this.pendingFile === undefined) { + this.data.otherAttachmentsComponent.openFile(this.attachment[0]); + } else { + if (this.pendingFile) { + const fileURL = URL.createObjectURL(this.pendingFile.file); + window.open(fileURL, '_blank'); + } } + } - deleteFile() { - this.pendingFile = undefined; - if (this.isEditing) { - this.attachmentForDelete = this.attachment; - } - this.attachment = []; + deleteFile() { + this.pendingFile = undefined; + if (this.isEditing) { + this.attachmentForDelete = this.attachment; } - - onChangeDescription() { - this.isDirty = true; - this.currentDescription = this.fileDescription.value; + this.attachment = []; + } + + onChangeDescription() { + this.isDirty = true; + this.currentDescription = this.fileDescription.value; + } + + onChangeType(selectedValue: DOCUMENT_TYPE) { + this.isDirty = true; + const newType = this.documentCodes.find((code) => code.code === selectedValue); + this.currentType = newType !== undefined ? newType : null; + } + + validateForm() { + if (this.form.valid && this.attachment.length !== 0) { + return true; } - onChangeType(selectedValue: DOCUMENT_TYPE) { - this.isDirty = true; - const newType = this.documentCodes.find((code) => code.code === selectedValue); - this.currentType = newType !== undefined ? newType : null; + if (this.form.invalid) { + this.form.markAllAsTouched(); } - validateForm() { - if (this.form.valid && this.attachment.length !== 0) { - return true; - } - - if (this.form.invalid) { - this.form.markAllAsTouched(); - } - - if (this.attachment.length == 0) { - this.showFileRequiredError = true; - } - return false; + if (this.attachment.length == 0) { + this.showFileRequiredError = true; } + return false; + } - async onAdd() { - if (this.validateForm()) { - await this.add(); - } + async onAdd() { + if (this.validateForm()) { + await this.add(); } - - protected async add() { - if (this.isFileDirty) { - this.isSaving = true; - const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); - this.showVirusError = !res; - if (res) { - const documents = await this.noticeOfIntentDocumentService.getByFileId(this.data.fileId); - if (documents) { - const sortedDocuments = documents.sort((a, b) => {return b.uploadedAt - a.uploadedAt}); - const updateDtos: NoticeOfIntentDocumentUpdateDto[] = sortedDocuments.map((file) => ({ - uuid: file.uuid, - description: file.description, - type: file.type?.code ?? null, - })); - updateDtos[0] = { - ...updateDtos[0], - description: this.currentDescription, - type: this.currentType?.code ?? null, - } - await this.noticeOfIntentDocumentService.update(this.data.fileId, updateDtos); - this.toastService.showSuccessToast('Attachment added successfully'); - this.dialogRef.close(); - } else { - this.toastService.showErrorToast("Could not read attached documents"); - } - } + } + + protected async add() { + if (this.isFileDirty) { + this.isSaving = true; + const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); + this.showVirusError = !res; + if (res) { + const documents = await this.noticeOfIntentDocumentService.getByFileId(this.data.fileId); + if (documents) { + const sortedDocuments = documents.sort((a, b) => { + return b.uploadedAt - a.uploadedAt; + }); + const updateDtos: NoticeOfIntentDocumentUpdateDto[] = sortedDocuments.map((file) => ({ + uuid: file.uuid, + description: file.description, + type: file.type?.code ?? null, + })); + updateDtos[0] = { + ...updateDtos[0], + description: this.currentDescription, + type: this.currentType?.code ?? null, + }; + await this.noticeOfIntentDocumentService.update(this.data.fileId, updateDtos); + this.toastService.showSuccessToast('Attachment added successfully'); + this.dialogRef.close(); + } else { + this.toastService.showErrorToast('Could not read attached documents'); } + } } + } - async onEdit() { - if (this.validateForm()) { - await this.edit(); - } + async onEdit() { + if (this.validateForm()) { + await this.edit(); } - - protected async edit() { - if (this.isFileDirty) { - this.data.otherAttachmentsComponent.onDeleteFile(this.attachmentForDelete[0]); - await this.add(); - } else { - if (this.isDirty) { - this.isSaving = true; - const documents = await this.noticeOfIntentDocumentService.getByFileId(this.data.fileId); - if (documents) { - const updateDtos: NoticeOfIntentDocumentUpdateDto[] = documents.map((file) => ({ - uuid: file.uuid, - description: file.description, - type: file.type?.code ?? null, - })); - for (let i = 0; i < updateDtos.length; i++) { - if (updateDtos[i].uuid === this.data.existingDocument?.uuid) { - updateDtos[i] = { - ...updateDtos[i], - description: this.currentDescription, - type: this.currentType?.code ?? null, - } - } - } - await this.noticeOfIntentDocumentService.update(this.data.fileId, updateDtos); - this.toastService.showSuccessToast('Attachment updated successully'); - } else { - this.toastService.showErrorToast("Could not read attached documents"); - } + } + + protected async edit() { + if (this.isFileDirty) { + this.data.otherAttachmentsComponent.onDeleteFile(this.attachmentForDelete[0]); + await this.add(); + } else { + if (this.isDirty) { + this.isSaving = true; + const documents = await this.noticeOfIntentDocumentService.getByFileId(this.data.fileId); + if (documents) { + const updateDtos: NoticeOfIntentDocumentUpdateDto[] = documents.map((file) => ({ + uuid: file.uuid, + description: file.description, + type: file.type?.code ?? null, + })); + for (let i = 0; i < updateDtos.length; i++) { + if (updateDtos[i].uuid === this.data.existingDocument?.uuid) { + updateDtos[i] = { + ...updateDtos[i], + description: this.currentDescription, + type: this.currentType?.code ?? null, + }; } - this.dialogRef.close(); + } + await this.noticeOfIntentDocumentService.update(this.data.fileId, updateDtos); + this.toastService.showSuccessToast('Attachment updated successully'); + } else { + this.toastService.showErrorToast('Could not read attached documents'); } + } + this.dialogRef.close(); } + } - private async loadDocumentCodes() { - const codes = await this.codeService.loadCodes(); - this.documentCodes = codes.documentTypes; - this.selectableTypes = this.documentCodes.filter((code) => USER_CONTROLLED_TYPES.includes(code.code)); - } + private async loadDocumentCodes() { + const codes = await this.codeService.loadCodes(); + this.documentCodes = codes.documentTypes; + this.selectableTypes = this.documentCodes.filter((code) => USER_CONTROLLED_TYPES.includes(code.code)); + } } diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html index 31b643215e..88e59043bc 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html @@ -239,6 +239,7 @@ [showErrors]="showErrors" [isRequired]="isCertificateOfTitleRequired" [showVirusError]="showVirusError" + [showServerError]="showServerError" [disabled]="parcelForm.controls.pid.disabled" >
@@ -347,11 +348,12 @@
OR
+ (editClicked)="onEditCrownOwner(selectedOwner)" + >
@@ -370,18 +372,20 @@
OR
- - + [ngClass]="{ error: ownerInput.errors && ownerInput.errors['required'] }" + > +
- {{owner.firstName + ' ' + owner.lastName}} + {{ owner.firstName + ' ' + owner.lastName }}
@@ -401,7 +405,7 @@
OR
'error-outline': enableUserSignOff && isConfirmedByApplicant.invalid && - (isConfirmedByApplicant.dirty || isConfirmedByApplicant.touched) + (isConfirmedByApplicant.dirty || isConfirmedByApplicant.touched), }" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts index aab4dbddbb..e5a6bac563 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts @@ -67,6 +67,7 @@ export class ParcelEntryComponent implements OnInit { isCrownLand: boolean | null = null; isCertificateOfTitleRequired = true; showVirusError = false; + showServerError = false; isMobile = false; parcelType = new FormControl(null, [Validators.required]); diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html index c30b61a893..c73e37f84d 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html @@ -219,6 +219,7 @@

[showErrors]="showErrors" [isRequired]="needsAuthorizationLetter" [showVirusError]="showVirusError" + [showServerError]="showServerError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts index 31eaaa9fbd..67e6de3976 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts @@ -38,6 +38,7 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni needsAuthorizationLetter = false; showVirusError = false; + showServerError = false; selectedThirdPartyAgent: boolean | null = false; selectedLocalGovernment = false; _selectedOwnerUuid: string | undefined = undefined; diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html index 6b8472096d..33de034b54 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html @@ -278,6 +278,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" > @@ -373,6 +374,7 @@

Proposal

[allowMultiple]="true" [disabled]="!allowMiningUploads" [showVirusError]="showCrossSectionVirus" + [showServerError]="showCrossSectionServerError" >
@@ -401,6 +403,7 @@

Proposal

[allowMultiple]="true" [disabled]="!allowMiningUploads" [showVirusError]="showReclamationPlanVirus" + [showServerError]="showReclamationPlanServerError" >
@@ -465,6 +468,7 @@

Proposal

[disabled]="!requiresNoticeOfWork" [allowMultiple]="true" [showVirusError]="showNoticeOfWorkVirus" + [showServerError]="showNoticeOfWorkServerError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts index dc2ab961cd..769fd39a04 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts @@ -35,9 +35,13 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, allowMiningUploads = false; requiresNoticeOfWork = false; showProposalMapVirus = false; + showProposalMapServerError = false; showCrossSectionVirus = false; + showCrossSectionServerError = false; showReclamationPlanVirus = false; + showReclamationPlanServerError = false; showNoticeOfWorkVirus = false; + showNoticeOfWorkServerError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html index 5b4768f031..b9877f0e5a 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html @@ -196,6 +196,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" > @@ -251,6 +252,7 @@

Proposal

[allowMultiple]="true" [disabled]="!allowMiningUploads" [showVirusError]="showCrossSectionVirus" + [showServerError]="showCrossSectionServerError" >
@@ -279,6 +281,7 @@

Proposal

[allowMultiple]="true" [disabled]="!allowMiningUploads" [showVirusError]="showReclamationPlanVirus" + [showServerError]="showReclamationPlanServerError" >
diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts index ab5f87f5a5..b657d97cfe 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts @@ -28,8 +28,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, allowMiningUploads = false; showProposalMapVirus = false; + showProposalMapServerError = false; showCrossSectionVirus = false; + showCrossSectionServerError = false; showReclamationPlanVirus = false; + showReclamationPlanServerError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html index 7f9b20bc25..db79c717dd 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html @@ -181,6 +181,7 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showProposalMapVirus" + [showServerError]="showProposalMapServerError" > @@ -240,6 +241,7 @@

Proposal

[allowMultiple]="true" [disabled]="!allowMiningUploads" [showVirusError]="showCrossSectionVirus" + [showServerError]="showCrossSectionServerError" >
@@ -268,6 +270,7 @@

Proposal

[allowMultiple]="true" [disabled]="!allowMiningUploads" [showVirusError]="showReclamationPlanVirus" + [showServerError]="showReclamationPlanServerError" >
@@ -325,6 +328,7 @@

Proposal

[disabled]="!requiresNoticeOfWork" [allowMultiple]="true" [showVirusError]="showNoticeOfWorkVirus" + [showServerError]="showNoticeOfWorkServerError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts index 356fe65147..ce326de054 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts @@ -29,9 +29,13 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, allowMiningUploads = false; requiresNoticeOfWork = false; showProposalMapVirus = false; + showProposalMapServerError = false; showCrossSectionVirus = false; + showCrossSectionServerError = false; showReclamationPlanVirus = false; + showReclamationPlanServerError = false; showNoticeOfWorkVirus = false; + showNoticeOfWorkServerError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 015de6d742..d4553a158b 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -1,82 +1,82 @@
-

{{title}} optional attachment

+

{{ title }} optional attachment

-
- - -
- - warning A virus was detected in the file. Choose another file and try again. - -
-
-
- - - - {{ type.label }} - - - -
- warning -
- This field is required -
-
-
-
- - - -
- warning -
- This field is required -
-
-
+
+ + +
+ + warning A virus was detected in the file. Choose another file and try again. + + +
+
+ + + + {{ type.label }} + + + +
+ warning +
This field is required
+
+
+
+ + + +
+ warning +
This field is required
- +
+
+
-
- - - -
+
+ + + +
diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index 65666c4581..cb9e0e1093 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -1,215 +1,224 @@ import { Component, Inject, type OnInit } from '@angular/core'; -import { FormControl, FormGroup, Validators } from "@angular/forms"; -import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; -import { NotificationDocumentDto, NotificationDocumentUpdateDto } from "../../../../../services/notification-document/notification-document.dto"; -import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from "../../../../../shared/dto/document.dto"; -import { FileHandle } from "../../../../../shared/file-drag-drop/drag-drop.directive"; -import { OtherAttachmentsComponent } from "../other-attachments.component"; -import { NotificationDocumentService } from "../../../../../services/notification-document/notification-document.service"; -import { CodeService } from "../../../../../services/code/code.service"; -import { ToastService } from "../../../../../services/toast/toast.service"; +import { FormControl, FormGroup, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { + NotificationDocumentDto, + NotificationDocumentUpdateDto, +} from '../../../../../services/notification-document/notification-document.dto'; +import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from '../../../../../shared/dto/document.dto'; +import { FileHandle } from '../../../../../shared/file-drag-drop/drag-drop.directive'; +import { OtherAttachmentsComponent } from '../other-attachments.component'; +import { NotificationDocumentService } from '../../../../../services/notification-document/notification-document.service'; +import { CodeService } from '../../../../../services/code/code.service'; +import { ToastService } from '../../../../../services/toast/toast.service'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @Component({ - selector: 'app-other-attachments-upload-dialog', - templateUrl: './other-attachments-upload-dialog.component.html', - styleUrl: './other-attachments-upload-dialog.component.scss', + selector: 'app-other-attachments-upload-dialog', + templateUrl: './other-attachments-upload-dialog.component.html', + styleUrl: './other-attachments-upload-dialog.component.scss', }) export class OtherAttachmentsUploadDialogComponent implements OnInit { - isDirty = false; - isFileDirty = false; - isSaving = false; - showVirusError = false; - showFileRequiredError = false; - title: string = ''; - isEditing = false; - - attachment: NotificationDocumentDto[] = []; - attachmentForDelete: NotificationDocumentDto[] = []; - pendingFile: FileHandle | undefined; - selectableTypes: DocumentTypeDto[] = []; - private documentCodes: DocumentTypeDto[] = []; - - fileDescription = new FormControl(null, [Validators.required]); - fileType = new FormControl(null, [Validators.required]); - currentDescription: string | null = null; - currentType: DocumentTypeDto | null = null; - - form = new FormGroup({ - fileDescription: this.fileDescription, - fileType: this.fileType, - }); - - constructor( - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) - public data: { - otherAttachmentsComponent: OtherAttachmentsComponent, - existingDocument?: NotificationDocumentDto, - fileId: string, - }, - private notificationDocumentService: NotificationDocumentService, - private codeService: CodeService, - private toastService: ToastService - ) {} - - ngOnInit(): void { - this.loadDocumentCodes(); - if (this.data.existingDocument) { - this.title = 'Edit'; - this.isEditing = true; - this.fileType.setValue(this.data.existingDocument.type!.code); - this.fileDescription.setValue(this.data.existingDocument.description!); - this.currentDescription = this.data.existingDocument.description!; - this.currentType = this.data.existingDocument.type; - this.attachment = [this.data.existingDocument]; - } else { - this.title = 'Add'; - } - } - - async attachDocument(file: FileHandle) { - this.pendingFile = file; - this.attachment = [{uuid: '', - fileName: file.file.name, - type: null, - fileSize: file.file.size, - uploadedBy: '', - uploadedAt: file.file.lastModified, - source: DOCUMENT_SOURCE.APPLICANT, - surveyPlanNumber: null, - controlNumber: null, - }]; - this.isFileDirty = true; - this.showFileRequiredError = true; + isDirty = false; + isFileDirty = false; + isSaving = false; + showVirusError = false; + showServerError = false; + showFileRequiredError = false; + title: string = ''; + isEditing = false; + + attachment: NotificationDocumentDto[] = []; + attachmentForDelete: NotificationDocumentDto[] = []; + pendingFile: FileHandle | undefined; + selectableTypes: DocumentTypeDto[] = []; + private documentCodes: DocumentTypeDto[] = []; + + fileDescription = new FormControl(null, [Validators.required]); + fileType = new FormControl(null, [Validators.required]); + currentDescription: string | null = null; + currentType: DocumentTypeDto | null = null; + + form = new FormGroup({ + fileDescription: this.fileDescription, + fileType: this.fileType, + }); + + constructor( + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) + public data: { + otherAttachmentsComponent: OtherAttachmentsComponent; + existingDocument?: NotificationDocumentDto; + fileId: string; + }, + private notificationDocumentService: NotificationDocumentService, + private codeService: CodeService, + private toastService: ToastService, + ) {} + + ngOnInit(): void { + this.loadDocumentCodes(); + if (this.data.existingDocument) { + this.title = 'Edit'; + this.isEditing = true; + this.fileType.setValue(this.data.existingDocument.type!.code); + this.fileDescription.setValue(this.data.existingDocument.description!); + this.currentDescription = this.data.existingDocument.description!; + this.currentType = this.data.existingDocument.type; + this.attachment = [this.data.existingDocument]; + } else { + this.title = 'Add'; } - - openFile() { - if (this.isEditing && this.pendingFile === undefined) { - this.data.otherAttachmentsComponent.openFile(this.attachment[0]); - } else { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile.file); - window.open(fileURL, '_blank'); - } - } + } + + async attachDocument(file: FileHandle) { + this.pendingFile = file; + this.attachment = [ + { + uuid: '', + fileName: file.file.name, + type: null, + fileSize: file.file.size, + uploadedBy: '', + uploadedAt: file.file.lastModified, + source: DOCUMENT_SOURCE.APPLICANT, + surveyPlanNumber: null, + controlNumber: null, + }, + ]; + this.isFileDirty = true; + this.showFileRequiredError = true; + } + + openFile() { + if (this.isEditing && this.pendingFile === undefined) { + this.data.otherAttachmentsComponent.openFile(this.attachment[0]); + } else { + if (this.pendingFile) { + const fileURL = URL.createObjectURL(this.pendingFile.file); + window.open(fileURL, '_blank'); + } } + } - deleteFile() { - this.pendingFile = undefined; - if (this.isEditing) { - this.attachmentForDelete = this.attachment; - } - this.attachment = []; + deleteFile() { + this.pendingFile = undefined; + if (this.isEditing) { + this.attachmentForDelete = this.attachment; } - - onChangeDescription() { - this.isDirty = true; - this.currentDescription = this.fileDescription.value; + this.attachment = []; + } + + onChangeDescription() { + this.isDirty = true; + this.currentDescription = this.fileDescription.value; + } + + onChangeType(selectedValue: DOCUMENT_TYPE) { + this.isDirty = true; + const newType = this.documentCodes.find((code) => code.code === selectedValue); + this.currentType = newType !== undefined ? newType : null; + } + + validateForm() { + if (this.form.valid && this.attachment.length !== 0) { + return true; } - onChangeType(selectedValue: DOCUMENT_TYPE) { - this.isDirty = true; - const newType = this.documentCodes.find((code) => code.code === selectedValue); - this.currentType = newType !== undefined ? newType : null; + if (this.form.invalid) { + this.form.markAllAsTouched(); } - validateForm() { - if (this.form.valid && this.attachment.length !== 0) { - return true; - } - - if (this.form.invalid) { - this.form.markAllAsTouched(); - } - - if (this.attachment.length == 0) { - this.showFileRequiredError = true; - } - return false; + if (this.attachment.length == 0) { + this.showFileRequiredError = true; } + return false; + } - async onAdd() { - if (this.validateForm()) { - await this.add(); - } + async onAdd() { + if (this.validateForm()) { + await this.add(); } - - protected async add() { - if (this.isFileDirty) { - this.isSaving = true; - const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); - this.showVirusError = !res; - if (res) { - const documents = await this.notificationDocumentService.getByFileId(this.data.fileId); - if (documents) { - const sortedDocuments = documents.sort((a, b) => {return b.uploadedAt - a.uploadedAt}); - const updateDtos: NotificationDocumentUpdateDto[] = sortedDocuments.map((file) => ({ - uuid: file.uuid, - description: file.description, - type: file.type?.code ?? null, - })); - updateDtos[0] = { - ...updateDtos[0], - description: this.currentDescription, - type: this.currentType?.code ?? null, - } - await this.notificationDocumentService.update(this.data.fileId, updateDtos); - this.toastService.showSuccessToast('Attachment added successfully'); - this.dialogRef.close(); - } else { - this.toastService.showErrorToast("Could not read attached documents"); - } - } - this.isDirty = false; - this.isFileDirty = true; - this.isSaving = false; + } + + protected async add() { + if (this.isFileDirty) { + this.isSaving = true; + const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); + this.showVirusError = !res; + if (res) { + const documents = await this.notificationDocumentService.getByFileId(this.data.fileId); + if (documents) { + const sortedDocuments = documents.sort((a, b) => { + return b.uploadedAt - a.uploadedAt; + }); + const updateDtos: NotificationDocumentUpdateDto[] = sortedDocuments.map((file) => ({ + uuid: file.uuid, + description: file.description, + type: file.type?.code ?? null, + })); + updateDtos[0] = { + ...updateDtos[0], + description: this.currentDescription, + type: this.currentType?.code ?? null, + }; + await this.notificationDocumentService.update(this.data.fileId, updateDtos); + this.toastService.showSuccessToast('Attachment added successfully'); + this.dialogRef.close(); + } else { + this.toastService.showErrorToast('Could not read attached documents'); } + } + this.isDirty = false; + this.isFileDirty = true; + this.isSaving = false; } + } - async onEdit() { - if (this.validateForm()) { - this.edit(); - } + async onEdit() { + if (this.validateForm()) { + this.edit(); } - - protected async edit() { - if (this.isFileDirty) { - this.data.otherAttachmentsComponent.onDeleteFile(this.attachmentForDelete[0]); - await this.onAdd(); - } else { - if (this.isDirty) { - this.isSaving = true; - const documents = await this.notificationDocumentService.getByFileId(this.data.fileId); - if (documents) { - const updateDtos: NotificationDocumentUpdateDto[] = documents.map((file) => ({ - uuid: file.uuid, - description: file.description, - type: file.type?.code ?? null, - })); - for (let i = 0; i < updateDtos.length; i++) { - if (updateDtos[i].uuid === this.data.existingDocument?.uuid) { - updateDtos[i] = { - ...updateDtos[i], - description: this.currentDescription, - type: this.currentType?.code ?? null, - } - } - } - await this.notificationDocumentService.update(this.data.fileId, updateDtos); - this.toastService.showSuccessToast('Attachment updated successully'); - } else { - this.toastService.showErrorToast("Could not read attached documents"); - } + } + + protected async edit() { + if (this.isFileDirty) { + this.data.otherAttachmentsComponent.onDeleteFile(this.attachmentForDelete[0]); + await this.onAdd(); + } else { + if (this.isDirty) { + this.isSaving = true; + const documents = await this.notificationDocumentService.getByFileId(this.data.fileId); + if (documents) { + const updateDtos: NotificationDocumentUpdateDto[] = documents.map((file) => ({ + uuid: file.uuid, + description: file.description, + type: file.type?.code ?? null, + })); + for (let i = 0; i < updateDtos.length; i++) { + if (updateDtos[i].uuid === this.data.existingDocument?.uuid) { + updateDtos[i] = { + ...updateDtos[i], + description: this.currentDescription, + type: this.currentType?.code ?? null, + }; } - this.dialogRef.close(); + } + await this.notificationDocumentService.update(this.data.fileId, updateDtos); + this.toastService.showSuccessToast('Attachment updated successully'); + } else { + this.toastService.showErrorToast('Could not read attached documents'); } + } + this.dialogRef.close(); } + } - private async loadDocumentCodes() { - const codes = await this.codeService.loadCodes(); - this.documentCodes = codes.documentTypes; - this.selectableTypes = this.documentCodes.filter((code) => USER_CONTROLLED_TYPES.includes(code.code)); - } + private async loadDocumentCodes() { + const codes = await this.codeService.loadCodes(); + this.documentCodes = codes.documentTypes; + this.selectableTypes = this.documentCodes.filter((code) => USER_CONTROLLED_TYPES.includes(code.code)); + } } diff --git a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html index 3f8d717121..889a803d9c 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html +++ b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html @@ -78,6 +78,7 @@

Purpose of SRW

[showErrors]="showErrors" [isRequired]="true" [showVirusError]="showSRWTermsVirus" + [showServerError]="showSRWTermsVirus" >
@@ -123,6 +124,7 @@

Purpose of SRW

[disabled]="!allowSurveyPlanUploads" [allowMultiple]="true" [showVirusError]="showSurveyPlanVirus" + [showServerError]="showSurveyPlanServerError" > diff --git a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts index 9e9dd6c25b..9f85926c04 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts @@ -49,7 +49,9 @@ export class ProposalComponent extends FilesStepComponent implements OnInit, OnD private isDirty = false; surveyForm = new FormGroup({} as any); showSRWTermsVirus = false; + showSRWTermsServerError = false; showSurveyPlanVirus = false; + showSurveyPlanServerError = false; constructor( private router: Router, diff --git a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html index aec322f1b2..afc2c8efcc 100644 --- a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html +++ b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html @@ -47,6 +47,7 @@
[showErrors]="showFileErrors" [isRequired]="true" [showVirusError]="showVirusError" + [showServerError]="showServerError" > diff --git a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts index 5946c65b8e..92991c5804 100644 --- a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts +++ b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts @@ -39,6 +39,7 @@ export class OwnerDialogComponent { isEdit = false; showVirusError = false; + showServerError = false; existingUuid: string | undefined; files: ApplicationDocumentDto[] = []; showFileErrors = false; From ffeccc1960187a8f33650d1a81e6b3851062fd4d Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:35:43 -0800 Subject: [PATCH 21/30] Strip error-handling and toasts from frontend services --- .../application-document.service.ts | 27 +++++-------------- .../application-owner.service.ts | 23 +++++----------- .../application-parcel.service.ts | 25 +++++------------ .../notice-of-intent-document.service.ts | 27 +++++-------------- .../notice-of-intent-owner.service.ts | 23 +++++----------- .../notice-of-intent-parcel.service.ts | 25 +++++------------ .../notification-document.service.ts | 27 +++++-------------- 7 files changed, 49 insertions(+), 128 deletions(-) diff --git a/portal-frontend/src/app/services/application-document/application-document.service.ts b/portal-frontend/src/app/services/application-document/application-document.service.ts index b7b69eab01..a4ce5b2153 100644 --- a/portal-frontend/src/app/services/application-document/application-document.service.ts +++ b/portal-frontend/src/app/services/application-document/application-document.service.ts @@ -27,26 +27,13 @@ export class ApplicationDocumentService { documentType: DOCUMENT_TYPE | null, source = DOCUMENT_SOURCE.APPLICANT ) { - try { - const res = await this.documentService.uploadFile( - fileNumber, - file, - documentType, - source, - `${this.serviceUrl}/application/${fileNumber}/attachExternal` - ); - if (res) { - this.toastService.showSuccessToast('Document uploaded'); - } - return res; - } catch (e) { - if (e instanceof HttpErrorResponse && e.status === 403) { - throw e; - } - console.error(e); - this.toastService.showErrorToast('Failed to attach document to Application, please try again'); - } - return undefined; + return await this.documentService.uploadFile( + fileNumber, + file, + documentType, + source, + `${this.serviceUrl}/application/${fileNumber}/attachExternal`, + ); } async openFile(fileUuid: string) { diff --git a/portal-frontend/src/app/services/application-owner/application-owner.service.ts b/portal-frontend/src/app/services/application-owner/application-owner.service.ts index 9124cb404f..feafe5b433 100644 --- a/portal-frontend/src/app/services/application-owner/application-owner.service.ts +++ b/portal-frontend/src/app/services/application-owner/application-owner.service.ts @@ -117,21 +117,12 @@ export class ApplicationOwnerService { } async uploadCorporateSummary(applicationFileId: string, file: File) { - try { - return await this.documentService.uploadFile<{ uuid: string }>( - applicationFileId, - file, - DOCUMENT_TYPE.CORPORATE_SUMMARY, - DOCUMENT_SOURCE.APPLICANT, - `${this.serviceUrl}/attachCorporateSummary` - ); - } catch (e) { - if (e instanceof HttpErrorResponse && e.status === 403) { - throw e; - } - console.error(e); - this.toastService.showErrorToast('Failed to attach document to Owner, please try again'); - } - return undefined; + return await this.documentService.uploadFile<{ uuid: string }>( + applicationFileId, + file, + DOCUMENT_TYPE.CORPORATE_SUMMARY, + DOCUMENT_SOURCE.APPLICANT, + `${this.serviceUrl}/attachCorporateSummary`, + ); } } diff --git a/portal-frontend/src/app/services/application-parcel/application-parcel.service.ts b/portal-frontend/src/app/services/application-parcel/application-parcel.service.ts index 65c8e9ac45..8891275130 100644 --- a/portal-frontend/src/app/services/application-parcel/application-parcel.service.ts +++ b/portal-frontend/src/app/services/application-parcel/application-parcel.service.ts @@ -73,24 +73,13 @@ export class ApplicationParcelService { } async attachCertificateOfTitle(fileId: string, parcelUuid: string, file: File) { - try { - const document = await this.documentService.uploadFile( - fileId, - file, - DOCUMENT_TYPE.CERTIFICATE_OF_TITLE, - DOCUMENT_SOURCE.APPLICANT, - `${environment.apiUrl}/application-parcel/${parcelUuid}/attachCertificateOfTitle` - ); - this.toastService.showSuccessToast('Document uploaded'); - return document; - } catch (e) { - if (e instanceof HttpErrorResponse && e.status === 403) { - throw e; - } - console.error(e); - this.toastService.showErrorToast('Failed to attach document to Parcel, please try again'); - } - return undefined; + return await this.documentService.uploadFile( + fileId, + file, + DOCUMENT_TYPE.CERTIFICATE_OF_TITLE, + DOCUMENT_SOURCE.APPLICANT, + `${environment.apiUrl}/application-parcel/${parcelUuid}/attachCertificateOfTitle`, + ); } async deleteMany(parcelUuids: string[]) { diff --git a/portal-frontend/src/app/services/notice-of-intent-document/notice-of-intent-document.service.ts b/portal-frontend/src/app/services/notice-of-intent-document/notice-of-intent-document.service.ts index 40461754d6..b2593f56d0 100644 --- a/portal-frontend/src/app/services/notice-of-intent-document/notice-of-intent-document.service.ts +++ b/portal-frontend/src/app/services/notice-of-intent-document/notice-of-intent-document.service.ts @@ -27,26 +27,13 @@ export class NoticeOfIntentDocumentService { documentType: DOCUMENT_TYPE | null, source = DOCUMENT_SOURCE.APPLICANT ) { - try { - const res = await this.documentService.uploadFile( - fileNumber, - file, - documentType, - source, - `${this.serviceUrl}/notice-of-intent/${fileNumber}/attachExternal` - ); - if (res) { - this.toastService.showSuccessToast('Document uploaded'); - } - return res; - } catch (e) { - if (e instanceof HttpErrorResponse && e.status === 403) { - throw e; - } - console.error(e); - this.toastService.showErrorToast('Failed to attach document, please try again'); - } - return undefined; + return await this.documentService.uploadFile( + fileNumber, + file, + documentType, + source, + `${this.serviceUrl}/notice-of-intent/${fileNumber}/attachExternal`, + ); } async openFile(fileUuid: string) { diff --git a/portal-frontend/src/app/services/notice-of-intent-owner/notice-of-intent-owner.service.ts b/portal-frontend/src/app/services/notice-of-intent-owner/notice-of-intent-owner.service.ts index eee2f7b09c..fd8d5c6ccc 100644 --- a/portal-frontend/src/app/services/notice-of-intent-owner/notice-of-intent-owner.service.ts +++ b/portal-frontend/src/app/services/notice-of-intent-owner/notice-of-intent-owner.service.ts @@ -127,21 +127,12 @@ export class NoticeOfIntentOwnerService { } async uploadCorporateSummary(noticeOfIntentFileId: string, file: File) { - try { - return await this.documentService.uploadFile<{ uuid: string }>( - noticeOfIntentFileId, - file, - DOCUMENT_TYPE.CORPORATE_SUMMARY, - DOCUMENT_SOURCE.APPLICANT, - `${this.serviceUrl}/attachCorporateSummary` - ); - } catch (e) { - if (e instanceof HttpErrorResponse && e.status === 403) { - throw e; - } - console.error(e); - this.toastService.showErrorToast('Failed to attach document to Owner, please try again'); - } - return undefined; + return await this.documentService.uploadFile<{ uuid: string }>( + noticeOfIntentFileId, + file, + DOCUMENT_TYPE.CORPORATE_SUMMARY, + DOCUMENT_SOURCE.APPLICANT, + `${this.serviceUrl}/attachCorporateSummary`, + ); } } diff --git a/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.ts b/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.ts index d7ab1c5f42..2a00ea82f1 100644 --- a/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.ts +++ b/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.ts @@ -73,24 +73,13 @@ export class NoticeOfIntentParcelService { } async attachCertificateOfTitle(fileId: string, parcelUuid: string, file: File) { - try { - const document = await this.documentService.uploadFile( - fileId, - file, - DOCUMENT_TYPE.CERTIFICATE_OF_TITLE, - DOCUMENT_SOURCE.APPLICANT, - `${this.serviceUrl}/${parcelUuid}/attachCertificateOfTitle` - ); - this.toastService.showSuccessToast('Document uploaded'); - return document; - } catch (e) { - if (e instanceof HttpErrorResponse && e.status === 403) { - throw e; - } - console.error(e); - this.toastService.showErrorToast('Failed to attach document to Parcel, please try again'); - } - return undefined; + return await this.documentService.uploadFile( + fileId, + file, + DOCUMENT_TYPE.CERTIFICATE_OF_TITLE, + DOCUMENT_SOURCE.APPLICANT, + `${this.serviceUrl}/${parcelUuid}/attachCertificateOfTitle`, + ); } async deleteMany(parcelUuids: string[]) { diff --git a/portal-frontend/src/app/services/notification-document/notification-document.service.ts b/portal-frontend/src/app/services/notification-document/notification-document.service.ts index 698ecbae19..5a462832a6 100644 --- a/portal-frontend/src/app/services/notification-document/notification-document.service.ts +++ b/portal-frontend/src/app/services/notification-document/notification-document.service.ts @@ -27,26 +27,13 @@ export class NotificationDocumentService { documentType: DOCUMENT_TYPE | null, source = DOCUMENT_SOURCE.APPLICANT ) { - try { - const res = await this.documentService.uploadFile( - fileNumber, - file, - documentType, - source, - `${this.serviceUrl}/notification/${fileNumber}/attachExternal` - ); - if (res) { - this.toastService.showSuccessToast('Document uploaded'); - } - return res; - } catch (e) { - if (e instanceof HttpErrorResponse && e.status === 403) { - throw e; - } - console.error(e); - this.toastService.showErrorToast('Failed to attach document, please try again'); - } - return undefined; + return await this.documentService.uploadFile( + fileNumber, + file, + documentType, + source, + `${this.serviceUrl}/notification/${fileNumber}/attachExternal`, + ); } async openFile(fileUuid: string) { From e59bfa9d01199b6d2e98a60a206f257ff39ccd7e Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:06:46 -0800 Subject: [PATCH 22/30] Make sure all upload components have toasts --- .../applications/edit-submission/files-step.partial.ts | 1 + .../parcel-details/parcel-entry/parcel-entry.component.ts | 1 + .../review-attachments/review-attachments.component.ts | 1 + .../notice-of-intents/edit-submission/files-step.partial.ts | 1 + .../parcels/parcel-entry/parcel-entry.component.ts | 1 + .../notifications/edit-submission/files-step.partial.ts | 1 + .../owner-dialogs/owner-dialog/owner-dialog.component.ts | 4 ++++ 7 files changed, 10 insertions(+) diff --git a/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts b/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts index b57fbfa6a2..4fcab93dd0 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts @@ -49,6 +49,7 @@ export abstract class FilesStepComponent extends StepComponent { } if (res) { + this.toastService.showSuccessToast('Document uploaded'); const documents = await this.applicationDocumentService.getByFileId(this.fileId); if (documents) { this.$applicationDocuments.next(documents); diff --git a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts index 1acb18112b..ce579b90f3 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts @@ -308,6 +308,7 @@ export class ParcelEntryComponent implements OnInit { parcelUuid, mappedFiles, ); + this.toastService.showSuccessToast('Document uploaded'); } catch (e) { this.showVirusError = true; this.toastService.showErrorToast('Document upload failed'); diff --git a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts index 4fd6313af8..6f017eaef5 100644 --- a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts +++ b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts @@ -112,6 +112,7 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { documentType, DOCUMENT_SOURCE.LFNG ); + this.toastService.showSuccessToast('Document uploaded'); } catch (e) { this.toastService.showErrorToast('Document upload failed'); return false; diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts index a3dcebd03f..19e40a4f0d 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts @@ -49,6 +49,7 @@ export abstract class FilesStepComponent extends StepComponent { } if (res) { + this.toastService.showSuccessToast('Document uploaded'); const documents = await this.noticeOfIntentDocumentService.getByFileId(this.fileId); if (documents) { this.$noiDocuments.next(documents); diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts index e5a6bac563..a31aceb7d9 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts @@ -312,6 +312,7 @@ export class ParcelEntryComponent implements OnInit { parcelUuid, mappedFiles, ); + this.toastService.showSuccessToast('Document uploaded'); } catch (e) { this.showVirusError = true; this.toastService.showErrorToast('Document upload failed'); diff --git a/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts b/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts index 9cc0e19699..58ccf6166f 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts @@ -49,6 +49,7 @@ export abstract class FilesStepComponent extends StepComponent { } if (res) { + this.toastService.showSuccessToast('Document uploaded'); const documents = await this.notificationDocumentService.getByFileId(this.fileId); if (documents) { this.$notificationDocuments.next(documents); diff --git a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts index 92991c5804..3f4b519280 100644 --- a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts +++ b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts @@ -21,6 +21,7 @@ import { OWNER_TYPE } from '../../dto/owner.dto'; import { FileHandle } from '../../file-drag-drop/drag-drop.directive'; import { openFileInline } from '../../utils/file'; import { strictEmailValidator } from '../../validators/email-validator'; +import { ToastService } from '../../../services/toast/toast.service'; @Component({ selector: 'app-owner-dialog', @@ -72,6 +73,7 @@ export class OwnerDialogComponent { documentService: ApplicationDocumentService | NoticeOfIntentDocumentService; ownerService: ApplicationOwnerService | NoticeOfIntentOwnerService; }, + private toastService: ToastService, ) { if (data && data.existingOwner) { this.onChangeType({ @@ -272,11 +274,13 @@ export class OwnerDialogComponent { if (file) { try { documentUuid = await this.data.ownerService.uploadCorporateSummary(this.data.fileId, file); + this.toastService.showSuccessToast('Document uploaded'); } catch (e) { this.showVirusError = true; this.pendingFile = undefined; this.corporateSummary.setValue(null); this.files = []; + this.toastService.showErrorToast('Document upload failed'); return; } } From e22051aea333a7b9adc0396f216e700f6bdfb7bd Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 07:40:10 -0800 Subject: [PATCH 23/30] Allow setting name property on API exceptions --- .../common/src/exceptions/base.exception.ts | 19 ++++++++++++------- .../common/src/exceptions/exception.filter.ts | 4 +--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/services/libs/common/src/exceptions/base.exception.ts b/services/libs/common/src/exceptions/base.exception.ts index 67eb664186..aecd69a9be 100644 --- a/services/libs/common/src/exceptions/base.exception.ts +++ b/services/libs/common/src/exceptions/base.exception.ts @@ -1,32 +1,37 @@ import { HttpException, HttpStatus } from '@nestjs/common'; export class BaseErrorResponseModel { - constructor(statusCode: number, message: string, path?: string) { + constructor(statusCode: number, name: string, message: string, path?: string) { this.statusCode = statusCode; + this.name = name; this.message = message; this.path = path; } statusCode: number; - path: string | undefined; + name: string; message: string; + path: string | undefined; } export class BaseServiceException extends HttpException { - constructor(error: string | Record, status?: number) { + constructor(error: string | Record, status?: number, name?: string) { super(error, status ?? HttpStatus.INTERNAL_SERVER_ERROR); + if (name) { + this.name = name; + } } } export class ServiceValidationException extends BaseServiceException { - constructor(error: string | Record) { - super(error, HttpStatus.BAD_REQUEST); + constructor(error: string | Record, name?: string) { + super(error, HttpStatus.BAD_REQUEST, name); } } export class ServiceNotFoundException extends BaseServiceException { - constructor(error: string | Record) { - super(error, HttpStatus.NOT_FOUND); + constructor(error: string | Record, name?: string) { + super(error, HttpStatus.NOT_FOUND, name); } } diff --git a/services/libs/common/src/exceptions/exception.filter.ts b/services/libs/common/src/exceptions/exception.filter.ts index dd2f50a04c..02bf8d3577 100644 --- a/services/libs/common/src/exceptions/exception.filter.ts +++ b/services/libs/common/src/exceptions/exception.filter.ts @@ -14,8 +14,6 @@ export class HttpExceptionFilter implements ExceptionFilter { this.logger.error(exception); - response - .status(status) - .send(new BaseErrorResponseModel(status, exception.message, request.url)); + response.status(status).send(new BaseErrorResponseModel(status, exception.name, exception.message, request.url)); } } From 4965f19dba68eb12567d816d3a6f943b64adefc7 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 07:42:10 -0800 Subject: [PATCH 24/30] Set name for ClamAV errors --- services/apps/alcs/src/document/document.service.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/apps/alcs/src/document/document.service.ts b/services/apps/alcs/src/document/document.service.ts index 2e1259546f..bf0fe1b866 100644 --- a/services/apps/alcs/src/document/document.service.ts +++ b/services/apps/alcs/src/document/document.service.ts @@ -166,13 +166,17 @@ export class DocumentService { if (isInfected === null || isInfected === undefined) { await this.deleteDocument(data.fileKey); this.logger.warn(`Deleted unscanned file ${data.fileKey}`); - throw new BaseServiceException('Virus scan failed, cannot determine if infected, upload blocked'); + throw new BaseServiceException( + 'Virus scan failed, cannot determine if infected, upload blocked', + undefined, + 'VirusScanFailed', + ); } if (isInfected) { await this.deleteDocument(data.fileKey); this.logger.warn(`Deleted malicious file ${data.fileKey}`); - throw new ServiceValidationException('File may contain malicious data, upload blocked'); + throw new ServiceValidationException('File may contain malicious data, upload blocked :P', 'VirusDetected'); } return this.documentRepository.save( From a8de4965de775077c1a718ce9b89a0769b3ae242 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 07:59:13 -0800 Subject: [PATCH 25/30] For files step, just re-throw errors --- .../edit-submission/files-step.partial.ts | 23 ++++++++----------- .../edit-submission/files-step.partial.ts | 23 ++++++++----------- .../edit-submission/files-step.partial.ts | 23 ++++++++----------- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts b/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts index 4fcab93dd0..f3fcaf1be9 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/files-step.partial.ts @@ -38,25 +38,22 @@ export abstract class FilesStepComponent extends StepComponent { await this.save(); const mappedFiles = file.file; - let res; try { - res = await this.applicationDocumentService.attachExternalFile(this.fileId, mappedFiles, documentType); + const res = await this.applicationDocumentService.attachExternalFile(this.fileId, mappedFiles, documentType); + + if (res) { + this.toastService.showSuccessToast('Document uploaded'); + const documents = await this.applicationDocumentService.getByFileId(this.fileId); + if (documents) { + this.$applicationDocuments.next(documents); + } + } } catch (err) { this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - return false; - } - } - if (res) { - this.toastService.showSuccessToast('Document uploaded'); - const documents = await this.applicationDocumentService.getByFileId(this.fileId); - if (documents) { - this.$applicationDocuments.next(documents); - } + throw err; } } - return true; } async onDeleteFile($event: ApplicationDocumentDto) { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts index 19e40a4f0d..b57663de3f 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/files-step.partial.ts @@ -38,25 +38,22 @@ export abstract class FilesStepComponent extends StepComponent { await this.save(); const mappedFiles = file.file; - let res; try { - res = await this.noticeOfIntentDocumentService.attachExternalFile(this.fileId, mappedFiles, documentType); + const res = await this.noticeOfIntentDocumentService.attachExternalFile(this.fileId, mappedFiles, documentType); + + if (res) { + this.toastService.showSuccessToast('Document uploaded'); + const documents = await this.noticeOfIntentDocumentService.getByFileId(this.fileId); + if (documents) { + this.$noiDocuments.next(documents); + } + } } catch (err) { this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - return false; - } - } - if (res) { - this.toastService.showSuccessToast('Document uploaded'); - const documents = await this.noticeOfIntentDocumentService.getByFileId(this.fileId); - if (documents) { - this.$noiDocuments.next(documents); - } + throw err; } } - return true; } async onDeleteFile($event: NoticeOfIntentDocumentDto) { diff --git a/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts b/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts index 58ccf6166f..a79c762e00 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/files-step.partial.ts @@ -38,25 +38,22 @@ export abstract class FilesStepComponent extends StepComponent { await this.save(); const mappedFiles = file.file; - let res; try { - res = await this.notificationDocumentService.attachExternalFile(this.fileId, mappedFiles, documentType); + const res = await this.notificationDocumentService.attachExternalFile(this.fileId, mappedFiles, documentType); + + if (res) { + this.toastService.showSuccessToast('Document uploaded'); + const documents = await this.notificationDocumentService.getByFileId(this.fileId); + if (documents) { + this.$notificationDocuments.next(documents); + } + } } catch (err) { this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - return false; - } - } - if (res) { - this.toastService.showSuccessToast('Document uploaded'); - const documents = await this.notificationDocumentService.getByFileId(this.fileId); - if (documents) { - this.$notificationDocuments.next(documents); - } + throw err; } } - return true; } //Using ApplicationDocumentDto is "correct" here, quack quack From c509b6b7fd627952a8828a68d84ac21cc759eac3 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:13:53 -0800 Subject: [PATCH 26/30] Update all portal instances --- ...r-attachments-upload-dialog.component.html | 5 +- ...her-attachments-upload-dialog.component.ts | 26 ++++- .../other-attachments.component.ts | 33 ++++-- .../parcel-entry/parcel-entry.component.html | 38 ++++--- .../parcel-entry/parcel-entry.component.ts | 22 ++-- .../primary-contact.component.html | 7 +- .../primary-contact.component.ts | 20 +++- .../cove-proposal.component.html | 17 +-- .../cove-proposal/cove-proposal.component.ts | 41 +++++-- .../excl-proposal.component.html | 23 ++-- .../excl-proposal/excl-proposal.component.ts | 87 +++++++++++---- .../incl-proposal.component.html | 25 +++-- .../incl-proposal/incl-proposal.component.ts | 89 +++++++++++---- .../naru-proposal.component.html | 15 ++- .../naru-proposal/naru-proposal.component.ts | 41 +++++-- .../nfu-proposal/nfu-proposal.component.html | 5 +- .../nfu-proposal/nfu-proposal.component.ts | 21 +++- .../pfrs-proposal.component.html | 51 ++++++--- .../pfrs-proposal/pfrs-proposal.component.ts | 101 ++++++++++++++---- .../pofo-proposal.component.html | 46 +++++--- .../pofo-proposal/pofo-proposal.component.ts | 81 +++++++++++--- .../roso-proposal.component.html | 46 +++++--- .../roso-proposal/roso-proposal.component.ts | 81 +++++++++++--- .../subd-proposal.component.html | 14 +-- .../subd-proposal/subd-proposal.component.ts | 43 ++++++-- .../tur-proposal/tur-proposal.component.html | 12 ++- .../tur-proposal/tur-proposal.component.ts | 43 ++++++-- .../review-attachments.component.html | 15 +-- .../review-attachments.component.ts | 74 +++++++++---- .../additional-information.component.html | 50 ++++++--- .../additional-information.component.ts | 21 +++- ...r-attachments-upload-dialog.component.html | 5 +- ...her-attachments-upload-dialog.component.ts | 24 ++++- .../other-attachments.component.ts | 33 ++++-- .../parcel-entry/parcel-entry.component.html | 5 +- .../parcel-entry/parcel-entry.component.ts | 21 ++-- .../primary-contact.component.html | 7 +- .../primary-contact.component.ts | 21 +++- .../pfrs/pfrs-proposal.component.html | 36 ++++--- .../proposal/pfrs/pfrs-proposal.component.ts | 83 +++++++++++--- .../pofo/pofo-proposal.component.html | 23 ++-- .../proposal/pofo/pofo-proposal.component.ts | 59 +++++++--- .../roso/roso-proposal.component.html | 32 +++--- .../proposal/roso/roso-proposal.component.ts | 83 +++++++++++--- ...r-attachments-upload-dialog.component.html | 7 +- ...her-attachments-upload-dialog.component.ts | 21 +++- .../other-attachments.component.ts | 33 ++++-- .../proposal/proposal.component.html | 14 +-- .../proposal/proposal.component.ts | 41 +++++-- .../file-drag-drop.component.html | 13 ++- .../file-drag-drop.component.ts | 5 +- .../owner-dialog/owner-dialog.component.html | 5 +- .../owner-dialog/owner-dialog.component.ts | 30 ++++-- 53 files changed, 1325 insertions(+), 469 deletions(-) diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 7243a693d3..1f1c471575 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -10,8 +10,9 @@

{{ title }} optional attachment

[uploadedFiles]="attachment" [showErrors]="showFileRequiredError" [isRequired]="true" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index e401b8c361..c07bac2a9a 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -12,6 +12,7 @@ import { OtherAttachmentsComponent } from '../other-attachments.component'; import { DOCUMENT_SOURCE, DOCUMENT_TYPE, DocumentTypeDto } from '../../../../../shared/dto/document.dto'; import { CodeService } from '../../../../../services/code/code.service'; import { FileHandle } from '../../../../../shared/file-drag-drop/drag-drop.directive'; +import { HttpErrorResponse } from '@angular/common/http'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @@ -24,8 +25,9 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { isDirty = false; isFileDirty = false; isSaving = false; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; showFileRequiredError = false; title: string = ''; isEditing = false; @@ -145,10 +147,14 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { protected async add() { if (this.isFileDirty) { this.isSaving = true; - const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); - this.showVirusError = !res; - if (res) { + try { + await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + const documents = await this.applicationDcoumentService.getByFileId(this.data.fileId); + if (documents) { const sortedDocuments = documents.sort((a, b) => { return b.uploadedAt - a.uploadedAt; @@ -168,9 +174,19 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { this.dialogRef.close(); } else { this.toastService.showErrorToast('Could not read attached documents'); + this.showUnknownError = true; + } + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } } + this.isDirty = false; + this.isFileDirty = true; + this.isSaving = false; } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async onEdit() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts index 51ad7db354..b3d0a788e1 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts @@ -17,6 +17,7 @@ import { EditApplicationSteps } from '../edit-submission.component'; import { FilesStepComponent } from '../files-step.partial'; import { OtherAttachmentsUploadDialogComponent } from './other-attachments-upload-dialog/other-attachments-upload-dialog.component'; import { MOBILE_BREAKPOINT } from '../../../../shared/utils/breakpoints'; +import { HttpErrorResponse } from '@angular/common/http'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @@ -33,7 +34,9 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI otherFiles: ApplicationDocumentDto[] = []; private isDirty = false; - showVirusError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; isMobile = window.innerWidth <= MOBILE_BREAKPOINT; form = new FormGroup({} as any); @@ -45,7 +48,7 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI private codeService: CodeService, applicationDocumentService: ApplicationDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(applicationDocumentService, dialog, toastService); } @@ -74,8 +77,18 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI } async attachDocument(file: FileHandle) { - const res = await this.attachFile(file, null); - this.showVirusError = !res; + try { + await this.attachFile(file, null); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showUnknownError = !this.showHasVirusError || !this.showVirusScanFailedError; + } } protected async save() { @@ -98,15 +111,17 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI onAddEditAttachment(attachment: ApplicationDocumentDto | undefined) { this.dialog .open(OtherAttachmentsUploadDialogComponent, { - width: this.isMobile? '90%' : '50%', + width: this.isMobile ? '90%' : '50%', data: { fileId: this.fileId, otherAttachmentsComponent: this, existingDocument: attachment, - } - }).afterClosed().subscribe(async res => { - await this.refreshFiles(); - }); + }, + }) + .afterClosed() + .subscribe(async (res) => { + await this.refreshFiles(); + }); } @HostListener('window:resize', ['$event']) diff --git a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html index 39fcef1a7d..81a747f01b 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html @@ -241,8 +241,9 @@ (beforeFileUploadOpened)="saveParcelProgress()" [showErrors]="showErrors" [isRequired]="isCertificateOfTitleRequired" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" [disabled]="parcelForm.controls.pid.disabled" > @@ -354,11 +355,12 @@
OR
+ (editClicked)="onEditCrownOwner(selectedOwner)" + >
@@ -377,18 +379,20 @@
OR
- - + [ngClass]="{ error: ownerInput.errors && ownerInput.errors['required'] }" + > +
- {{owner.firstName + ' ' + owner.lastName}} + {{ owner.firstName + ' ' + owner.lastName }}
@@ -408,7 +412,7 @@
OR
'error-outline': enableUserSignOff && isConfirmedByApplicant.invalid && - (isConfirmedByApplicant.dirty || isConfirmedByApplicant.touched) + (isConfirmedByApplicant.dirty || isConfirmedByApplicant.touched), }" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts index ce579b90f3..13fe34df94 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts @@ -23,6 +23,7 @@ import { openFileInline } from '../../../../../shared/utils/file'; import { RemoveFileConfirmationDialogComponent } from '../../../alcs-edit-submission/remove-file-confirmation-dialog/remove-file-confirmation-dialog.component'; import { ParcelEntryConfirmationDialogComponent } from './parcel-entry-confirmation-dialog/parcel-entry-confirmation-dialog.component'; import { MOBILE_BREAKPOINT } from '../../../../../shared/utils/breakpoints'; +import { HttpErrorResponse } from '@angular/common/http'; export interface ParcelEntryFormData { uuid: string; @@ -57,8 +58,9 @@ export class ParcelEntryComponent implements OnInit { @Input() _disabled = false; @Input() isDraft = false; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; @Output() private onFormGroupChange = new EventEmitter>(); @Output() private onSaveProgress = new EventEmitter(); @@ -302,6 +304,7 @@ export class ParcelEntryComponent implements OnInit { async attachFile(file: FileHandle, parcelUuid: string) { if (parcelUuid) { const mappedFiles = file.file; + try { this.parcel.certificateOfTitle = await this.applicationParcelService.attachCertificateOfTitle( this.fileId, @@ -309,13 +312,20 @@ export class ParcelEntryComponent implements OnInit { mappedFiles, ); this.toastService.showSuccessToast('Document uploaded'); - } catch (e) { - this.showVirusError = true; - this.toastService.showErrorToast('Document upload failed'); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; return; + } catch (err) { + this.toastService.showErrorToast('Document upload failed'); + + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } } - this.showVirusError = false; } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async deleteFile($event: ApplicationDocumentDto) { diff --git a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html index 926ad3b58a..9709f936b6 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html @@ -82,7 +82,7 @@

Primary Contact

Phone Number:
-
{{ phoneNumber.value ?? '' | mask : '(000) 000-0000' }}
+
{{ phoneNumber.value ?? '' | mask: '(000) 000-0000' }}
Email:
@@ -217,8 +217,9 @@

(openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="needsAuthorizationLetter" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" >

diff --git a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts index 2f951256be..a568f11e23 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts @@ -22,6 +22,7 @@ import { CrownOwnerDialogComponent } from '../../../../shared/owner-dialogs/crow import { scrollToElement } from '../../../../shared/utils/scroll-helper'; import { MatButtonToggleChange } from '@angular/material/button-toggle'; import { strictEmailValidator } from '../../../../shared/validators/email-validator'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-primary-contact', @@ -43,8 +44,9 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni isGovernmentUser = false; governmentName: string | undefined; isDirty = false; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; hasCrownParcels = false; ownersList = new FormControl(null, [Validators.required]); @@ -103,8 +105,18 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni } async attachAuthorizationLetter(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.AUTHORIZATION_LETTER); - this.showVirusError = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.AUTHORIZATION_LETTER); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; + } } set selectedOwnerUuid(value: string | undefined) { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html index 89df02f198..aec5f2dc34 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html @@ -32,7 +32,7 @@

Proposal

mat-flat-button color="accent" [ngClass]="{ - 'error-outline': transferees.length === 0 && showErrors + 'error-outline': transferees.length === 0 && showErrors, }" (click)="onAdd()" > @@ -185,8 +185,10 @@

Proposal

(openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" >
@@ -202,7 +204,7 @@

Proposal

Yes @@ -210,7 +212,7 @@

Proposal

No @@ -230,8 +232,9 @@

Proposal

[showErrors]="showErrors" [isRequired]="true" [disabled]="!canUploadDraft" - [showVirusError]="showDraftCovenantVirus" - [showServerError]="showDraftCovenantServerError" + [showHasVirusError]="showDraftCovenantHasVirusError" + [showVirusScanFailedError]="showDraftCovenantVirusScanFailedError" + [showUnknownError]="showDraftCovenantUnknownError" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts index ed02d2ef7e..635574f8f6 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts @@ -20,6 +20,7 @@ import { CovenantTransfereeDialogComponent } from './transferee-dialog/transfere import { ConfirmationDialogService } from '../../../../../shared/confirmation-dialog/confirmation-dialog.service'; import { MOBILE_BREAKPOINT } from '../../../../../shared/utils/breakpoints'; import { VISIBLE_COUNT_INCREMENT } from '../../../../../shared/constants'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-cove-proposal', @@ -49,11 +50,13 @@ export class CoveProposalComponent extends FilesStepComponent implements OnInit, }); proposalMap: ApplicationDocumentDto[] = []; - showProposalMapVirus = false; - showProposalMapServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; draftCovenant: ApplicationDocumentDto[] = []; - showDraftCovenantVirus = false; - showDraftCovenantServerError = false; + showDraftCovenantHasVirusError = false; + showDraftCovenantVirusScanFailedError = false; + showDraftCovenantUnknownError = false; isMobile = false; visibleCount = VISIBLE_COUNT_INCREMENT; @@ -129,13 +132,35 @@ export class CoveProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachDraftCovenant(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.SRW_TERMS); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.SRW_TERMS); + this.showDraftCovenantHasVirusError = false; + this.showDraftCovenantVirusScanFailedError = false; + this.showDraftCovenantUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showDraftCovenantHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showDraftCovenantVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showDraftCovenantUnknownError = + !this.showDraftCovenantHasVirusError && !this.showDraftCovenantVirusScanFailedError; + } } onAdd() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html index 263241b30c..ccd8788161 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html @@ -134,8 +134,10 @@

Proposal

(openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -177,8 +179,10 @@

Notification and Public Hearing Requirements

[showErrors]="showErrors" [allowMultiple]="true" [isRequired]="true" - [showVirusError]="showProofOfAdvertisingVirus" - [showServerError]="showProofOfAdvertisingServerError" + [showHasVirusError]="showProofOfAdvertisingHasVirusError" + [showVirusScanFailedError]="showProofOfAdvertisingVirusScanFailedError" + [showVirusScanFailedError]="showProofOfAdvertisingVirusScanFailedError" + [showUnknownError]="showProofOfAdvertisingUnknownError" >
@@ -196,8 +200,10 @@

Notification and Public Hearing Requirements

[showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showProofOfSignageVirus" - [showServerError]="showProofOfSignageServerError" + [showHasVirusError]="showProofOfSignageHasVirusError" + [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" + [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" + [showUnknownError]="showProofOfSignageUnknownError" >
@@ -212,8 +218,9 @@

Notification and Public Hearing Requirements

[showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showReportOfPublicHearingVirus" - [showServerError]="showReportOfPublicHearingServerError" + [showHasVirusError]="showReportOfPublicHearingHasVirusError" + [showVirusScanFailedError]="showReportOfPublicHearingVirusScanFailedError" + [showUnknownError]="showReportOfPublicHearingUnknownError" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts index dbdb0f76e3..08fec7e13c 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts @@ -13,6 +13,7 @@ import { FileHandle } from '../../../../../shared/file-drag-drop/drag-drop.direc import { parseStringToBoolean } from '../../../../../shared/utils/string-helper'; import { EditApplicationSteps } from '../../edit-submission.component'; import { FilesStepComponent } from '../../files-step.partial'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-excl-proposal', @@ -25,14 +26,18 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, currentStep = EditApplicationSteps.Proposal; prescribedBody: string | null = null; - showProposalMapVirus = false; - showProposalMapServerError = false; - showProofOfAdvertisingVirus = false; - showProofOfAdvertisingServerError = false; - showProofOfSignageVirus = false; - showProofOfSignageServerError = false; - showReportOfPublicHearingVirus = false; - showReportOfPublicHearingServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showProofOfAdvertisingHasVirusError = false; + showProofOfAdvertisingVirusScanFailedError = false; + showProofOfAdvertisingUnknownError = false; + showProofOfSignageHasVirusError = false; + showProofOfSignageVirusScanFailedError = false; + showProofOfSignageUnknownError = false; + showReportOfPublicHearingHasVirusError = false; + showReportOfPublicHearingVirusScanFailedError = false; + showReportOfPublicHearingUnknownError = false; hectares = new FormControl(null, [Validators.required]); shareProperty = new FormControl(null, [Validators.required]); @@ -56,7 +61,7 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, private pdfGenerationService: PdfGenerationService, applicationDocumentService: ApplicationDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(applicationDocumentService, dialog, toastService); } @@ -87,11 +92,11 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, this.$applicationDocuments.pipe(takeUntil(this.$destroy)).subscribe((documents) => { this.proposalMap = documents.filter((document) => document.type?.code === DOCUMENT_TYPE.PROPOSAL_MAP); this.noticeOfPublicHearing = documents.filter( - (document) => document.type?.code === DOCUMENT_TYPE.PROOF_OF_ADVERTISING + (document) => document.type?.code === DOCUMENT_TYPE.PROOF_OF_ADVERTISING, ); this.proofOfSignage = documents.filter((document) => document.type?.code === DOCUMENT_TYPE.PROOF_OF_SIGNAGE); this.reportOfPublicHearing = documents.filter( - (document) => document.type?.code === DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING + (document) => document.type?.code === DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING, ); }); } @@ -101,23 +106,67 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachProofOfAdvertising(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_ADVERTISING); - this.showProofOfAdvertisingVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_ADVERTISING); + this.showProofOfAdvertisingHasVirusError = false; + this.showProofOfAdvertisingVirusScanFailedError = false; + this.showProofOfAdvertisingUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProofOfAdvertisingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProofOfAdvertisingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProofOfAdvertisingUnknownError = + !this.showProofOfAdvertisingHasVirusError && !this.showProofOfAdvertisingVirusScanFailedError; + } } async attachProofOfSignage(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_SIGNAGE); - this.showProofOfSignageVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_SIGNAGE); + this.showProofOfSignageHasVirusError = false; + this.showProofOfSignageVirusScanFailedError = false; + this.showProofOfSignageUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProofOfSignageHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProofOfSignageVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProofOfSignageUnknownError = + !this.showProofOfSignageHasVirusError && !this.showProofOfSignageVirusScanFailedError; + } } async attachReportOfPublicHearing(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING); - this.showReportOfPublicHearingVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING); + this.showReportOfPublicHearingHasVirusError = false; + this.showReportOfPublicHearingVirusScanFailedError = false; + this.showReportOfPublicHearingUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReportOfPublicHearingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReportOfPublicHearingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReportOfPublicHearingUnknownError = + !this.showReportOfPublicHearingHasVirusError && !this.showReportOfPublicHearingVirusScanFailedError; + } } async onDownloadPdf() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html index 9b1bb4b82c..4009d427d0 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html @@ -125,8 +125,9 @@

Proposal

(openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" >
@@ -157,7 +158,7 @@

Proposal

value="true" [ngClass]="{ 'error-outline': - governmentOwnsAllParcels.invalid && (governmentOwnsAllParcels.dirty || governmentOwnsAllParcels.touched) + governmentOwnsAllParcels.invalid && (governmentOwnsAllParcels.dirty || governmentOwnsAllParcels.touched), }" >Yes @@ -165,7 +166,7 @@

Proposal

value="false" [ngClass]="{ 'error-outline': - governmentOwnsAllParcels.invalid && (governmentOwnsAllParcels.dirty || governmentOwnsAllParcels.touched) + governmentOwnsAllParcels.invalid && (governmentOwnsAllParcels.dirty || governmentOwnsAllParcels.touched), }" >No @@ -215,8 +216,9 @@

Notification and Public Hearing Requirements

[isRequired]="!disableNotificationFileUploads" [disabled]="disableNotificationFileUploads" [allowMultiple]="true" - [showVirusError]="showProofOfAdvertisingVirus" - [showServerError]="showProofOfAdvertisingServerError" + [showHasVirusError]="showProofOfAdvertisingHasVirusError" + [showVirusScanFailedError]="showProofOfAdvertisingVirusScanFailedError" + [showUnknownError]="showProofOfAdvertisingUnknownError" >
@@ -235,8 +237,10 @@

Notification and Public Hearing Requirements

[isRequired]="!disableNotificationFileUploads" [disabled]="disableNotificationFileUploads" [allowMultiple]="true" - [showVirusError]="showProofOfSignageVirus" - [showServerError]="showProofOfSignageServerError" + [showHasVirusError]="showProofOfSignageHasVirusError" + [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" + [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" + [showUnknownError]="showProofOfSignageUnknownError" >
@@ -251,8 +255,9 @@

Notification and Public Hearing Requirements

[showErrors]="showErrors" [isRequired]="!disableNotificationFileUploads" [disabled]="disableNotificationFileUploads" - [showVirusError]="showReportOfPublicHearingVirus" - [showServerError]="showReportOfPublicHearingServerError" + [showHasVirusError]="showReportOfPublicHearingHasVirusError" + [showVirusScanFailedError]="showReportOfPublicHearingVirusScanFailedError" + [showUnknownError]="showReportOfPublicHearingUnknownError" [allowMultiple]="true" >
diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts index 588bf5eaf6..3fdd1be94b 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts @@ -15,6 +15,7 @@ import { ApplicationDocumentDto } from '../../../../../services/application-docu import { EditApplicationSteps } from '../../edit-submission.component'; import { takeUntil } from 'rxjs'; import { ApplicationSubmissionUpdateDto } from '../../../../../services/application-submission/application-submission.dto'; +import { HttpErrorResponse } from '@angular/common/http'; interface InclForm { hectares: FormControl; @@ -37,14 +38,18 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, governmentName? = ''; disableNotificationFileUploads = true; - showProposalMapVirus = false; - showProposalMapServerError = false; - showProofOfAdvertisingVirus = false; - showProofOfAdvertisingServerError = false; - showProofOfSignageVirus = false; - showProofOfSignageServerError = false; - showReportOfPublicHearingVirus = false; - showReportOfPublicHearingServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showProofOfAdvertisingHasVirusError = false; + showProofOfAdvertisingVirusScanFailedError = false; + showProofOfAdvertisingUnknownError = false; + showProofOfSignageHasVirusError = false; + showProofOfSignageVirusScanFailedError = false; + showProofOfSignageUnknownError = false; + showReportOfPublicHearingHasVirusError = false; + showReportOfPublicHearingVirusScanFailedError = false; + showReportOfPublicHearingUnknownError = false; hectares = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); @@ -69,7 +74,7 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, private authenticationService: AuthenticationService, applicationDocumentService: ApplicationDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(applicationDocumentService, dialog, toastService); } @@ -90,7 +95,7 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, if (applicationSubmission.inclGovernmentOwnsAllParcels !== null) { this.showGovernmentQuestions = true; this.governmentOwnsAllParcels.setValue( - formatBooleanToString(applicationSubmission.inclGovernmentOwnsAllParcels) + formatBooleanToString(applicationSubmission.inclGovernmentOwnsAllParcels), ); this.disableNotificationFileUploads = applicationSubmission.inclGovernmentOwnsAllParcels; this.form.setControl('governmentOwnsAllParcels', this.governmentOwnsAllParcels); @@ -105,11 +110,11 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, this.$applicationDocuments.pipe(takeUntil(this.$destroy)).subscribe((documents) => { this.proposalMap = documents.filter((document) => document.type?.code === DOCUMENT_TYPE.PROPOSAL_MAP); this.noticeOfPublicHearing = documents.filter( - (document) => document.type?.code === DOCUMENT_TYPE.PROOF_OF_ADVERTISING + (document) => document.type?.code === DOCUMENT_TYPE.PROOF_OF_ADVERTISING, ); this.proofOfSignage = documents.filter((document) => document.type?.code === DOCUMENT_TYPE.PROOF_OF_SIGNAGE); this.reportOfPublicHearing = documents.filter( - (document) => document.type?.code === DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING + (document) => document.type?.code === DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING, ); }); @@ -133,23 +138,67 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachProofOfAdvertising(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_ADVERTISING); - this.showProofOfAdvertisingVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_ADVERTISING); + this.showProofOfAdvertisingHasVirusError = false; + this.showProofOfAdvertisingVirusScanFailedError = false; + this.showProofOfAdvertisingUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProofOfAdvertisingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProofOfAdvertisingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProofOfAdvertisingUnknownError = + !this.showProofOfAdvertisingHasVirusError && !this.showProofOfAdvertisingVirusScanFailedError; + } } async attachProofOfSignage(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_SIGNAGE); - this.showProofOfSignageVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_SIGNAGE); + this.showProofOfSignageHasVirusError = false; + this.showProofOfSignageVirusScanFailedError = false; + this.showProofOfSignageUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProofOfSignageHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProofOfSignageVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProofOfSignageUnknownError = + !this.showProofOfSignageHasVirusError && !this.showProofOfSignageVirusScanFailedError; + } } async attachReportOfPublicHearing(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING); - this.showReportOfPublicHearingVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING); + this.showReportOfPublicHearingHasVirusError = false; + this.showReportOfPublicHearingVirusScanFailedError = false; + this.showReportOfPublicHearingUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReportOfPublicHearingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReportOfPublicHearingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReportOfPublicHearingUnknownError = + !this.showReportOfPublicHearingHasVirusError && !this.showReportOfPublicHearingVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html index 6a58a3ae21..5b1fd33158 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html @@ -23,10 +23,7 @@

Proposal

>
  • - + Housing in the ALR
  • @@ -642,8 +639,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -660,8 +658,9 @@

    Proposal

    (deleteFile)="onDeleteFile($event)" (openFile)="openFile($event)" [showErrors]="showErrors" - [showVirusError]="showBuildingPlanVirus" - [showServerError]="showBuildingPlanServerError" + [showHasVirusError]="showBuildingPlanHasVirusError" + [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" + [showUnknownError]="showBuildingPlanUnknownError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts index aef4cf2b7b..4043dcc7a6 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts @@ -21,6 +21,7 @@ import { ResidenceDialogComponent } from './residence-dialog/residence-dialog.co import { MOBILE_BREAKPOINT } from '../../../../../shared/utils/breakpoints'; import { isTruncated, truncate } from '../../../../../shared/utils/string-helper'; import { EXISTING_RESIDENCE_DESCRIPTION_CHAR_LIMIT } from '../../../../../shared/constants'; +import { HttpErrorResponse } from '@angular/common/http'; export type FormExisingResidence = { id?: number; floorArea: number; description: string; isExpanded?: boolean }; export type FormProposedResidence = { id?: number; floorArea: number; description: string; isExpanded?: boolean }; @@ -33,10 +34,12 @@ export type FormProposedResidence = { id?: number; floorArea: number; descriptio export class NaruProposalComponent extends FilesStepComponent implements OnInit, OnDestroy { currentStep = EditApplicationSteps.Proposal; - showProposalMapVirus = false; - showProposalMapServerError = false; - showBuildingPlanVirus = false; - showBuildingPlanServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showBuildingPlanHasVirusError = false; + showBuildingPlanVirusScanFailedError = false; + showBuildingPlanUnknownError = false; willBeOverFiveHundredM2 = new FormControl(null, [Validators.required]); willRetainResidence = new FormControl(null, [Validators.required]); @@ -181,13 +184,35 @@ export class NaruProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachBuildingPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); - this.showBuildingPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); + this.showBuildingPlanHasVirusError = false; + this.showBuildingPlanVirusScanFailedError = false; + this.showBuildingPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showBuildingPlanUnknownError = + !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; + } } onChangeOver500m2(answerIsYes: boolean) { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html index f687836913..3c97cf7715 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html @@ -120,8 +120,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts index 6d940e560c..b629a68b96 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts @@ -14,6 +14,7 @@ import { SoilTableData } from '../../../../../shared/soil-table/soil-table.compo import { EditApplicationSteps } from '../../edit-submission.component'; import { FilesStepComponent } from '../../files-step.partial'; import { ConfirmationDialogService } from '../../../../../shared/confirmation-dialog/confirmation-dialog.service'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-nfu-proposal', @@ -25,8 +26,9 @@ export class NfuProposalComponent extends FilesStepComponent implements OnInit, fillTableData: SoilTableData = {}; fillTableDisabled = true; - showProposalMapVirus = false; - showProposalMapServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; hectares = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); @@ -104,8 +106,19 @@ export class NfuProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html index c9b32aca50..46e9c47f1d 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html @@ -314,12 +314,22 @@

    Proposal

    - + - - -
    #{{ i + 1 }} + {{ i + 1 }} + Type + Proposal Total Floor Area + Proposal Action + @@ -683,8 +701,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -710,8 +729,9 @@

    Proposal

    [showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showCrossSectionVirus" - [showServerError]="showCrossSectionServerError" + [showHasVirusError]="showCrossSectionHasVirusError" + [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" + [showUnknownError]="showCrossSectionUnknownError" > @@ -739,8 +759,9 @@

    Proposal

    [showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showReclamationPlanVirus" - [showServerError]="showReclamationPlanServerError" + [showHasVirusError]="showReclamationPlanHasVirusError" + [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" + [showUnknownError]="showReclamationPlanUnknownError" > @@ -759,8 +780,9 @@

    Proposal

    (deleteFile)="onDeleteFile($event)" (openFile)="openFile($event)" [showErrors]="showErrors" - [showVirusError]="showBuildingPlanVirus" - [showServerError]="showBuildingPlanServerError" + [showHasVirusError]="showBuildingPlanHasVirusError" + [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" + [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="true" [allowMultiple]="true" > @@ -866,8 +888,9 @@

    Proposal

    [isRequired]="true" [disabled]="!requiresNoticeOfWork" [allowMultiple]="true" - [showVirusError]="showNoticeOfWorkVirus" - [showServerError]="showNoticeOfWorkServerError" + [showHasVirusError]="showNoticeOfWorkHasVirusError" + [showVirusScanFailedError]="showNoticeOfWorkVirusScanFailedError" + [showUnknownError]="showNoticeOfWorkUnknownError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts index c3679a0d1e..f95426e8e1 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts @@ -25,6 +25,7 @@ import { } from '../../../../notice-of-intents/edit-submission/additional-information/additional-information.component'; import { ProposedStructure } from '../../../../../services/notice-of-intent-submission/notice-of-intent-submission.dto'; import { AddStructureDialogComponent } from '../../../../notice-of-intents/edit-submission/additional-information/add-structure-dialog/add-structure-dialog.component'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-pfrs-proposal', @@ -54,16 +55,21 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, noticeOfWork: ApplicationDocumentDto[] = []; areComponentsDirty = false; - showProposalMapVirus = false; - showProposalMapServerError = false; - showCrossSectionVirus = false; - showCrossSectionServerError = false; - showReclamationPlanVirus = false; - showReclamationPlanServerError = false; - showBuildingPlanVirus = false; - showBuildingPlanServerError = false; - showNoticeOfWorkVirus = false; - showNoticeOfWorkServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showCrossSectionHasVirusError = false; + showCrossSectionVirusScanFailedError = false; + showCrossSectionUnknownError = false; + showReclamationPlanHasVirusError = false; + showReclamationPlanVirusScanFailedError = false; + showReclamationPlanUnknownError = false; + showBuildingPlanHasVirusError = false; + showBuildingPlanVirusScanFailedError = false; + showBuildingPlanUnknownError = false; + showNoticeOfWorkHasVirusError = false; + showNoticeOfWorkVirusScanFailedError = false; + showNoticeOfWorkUnknownError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); @@ -232,28 +238,83 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachCrossSection(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); - this.showCrossSectionVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); + this.showCrossSectionHasVirusError = false; + this.showCrossSectionVirusScanFailedError = false; + this.showCrossSectionUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showCrossSectionUnknownError = + !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; + } } async attachReclamationPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); - this.showReclamationPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); + this.showReclamationPlanHasVirusError = false; + this.showReclamationPlanVirusScanFailedError = false; + this.showReclamationPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReclamationPlanUnknownError = + !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; + } } async attachBuildingPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); - this.showBuildingPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); + this.showBuildingPlanHasVirusError = false; + this.showBuildingPlanVirusScanFailedError = false; + this.showBuildingPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showBuildingPlanUnknownError = + !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; + } } async attachNoticeOfWork(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); - this.showNoticeOfWorkVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); + this.showNoticeOfWorkHasVirusError = false; + this.showNoticeOfWorkVirusScanFailedError = false; + this.showNoticeOfWorkUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showNoticeOfWorkHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showNoticeOfWorkVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showNoticeOfWorkUnknownError = + !this.showNoticeOfWorkHasVirusError && !this.showNoticeOfWorkVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html index 8ce0e4c2e9..d11e6ad8ad 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html @@ -222,12 +222,22 @@

    Proposal

    - + - - -
    #{{ i + 1 }} + {{ i + 1 }} + Type + Proposal Total Floor Area + Proposal Action + @@ -593,8 +611,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -620,8 +639,9 @@

    Proposal

    [showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showCrossSectionVirus" - [showServerError]="showCrossSectionServerError" + [showHasVirusError]="showCrossSectionHasVirusError" + [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" + [showUnknownError]="showCrossSectionUnknownError" > @@ -649,8 +669,9 @@

    Proposal

    [showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showReclamationPlanVirus" - [showServerError]="showReclamationPlanServerError" + [showHasVirusError]="showReclamationPlanHasVirusError" + [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" + [showUnknownError]="showReclamationPlanUnknownError" > @@ -669,8 +690,9 @@

    Proposal

    (deleteFile)="onDeleteFile($event)" (openFile)="openFile($event)" [showErrors]="showErrors" - [showVirusError]="showBuildingPlanVirus" - [showServerError]="showBuildingPlanServerError" + [showHasVirusError]="showBuildingPlanHasVirusError" + [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" + [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="true" [allowMultiple]="true" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts index 68891874ab..861e6dcf58 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts @@ -26,6 +26,7 @@ import { MOBILE_BREAKPOINT } from '../../../../../shared/utils/breakpoints'; import { AddStructureDialogComponent } from '../../../../../features/notice-of-intents/edit-submission/additional-information/add-structure-dialog/add-structure-dialog.component'; import { ProposedStructure } from '../../../../../services/notice-of-intent-submission/notice-of-intent-submission.dto'; import { v4 } from 'uuid'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-pofo-proposal', @@ -53,14 +54,18 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, reclamationPlan: ApplicationDocumentDto[] = []; buildingPlans: ApplicationDocumentDto[] = []; - showProposalMapVirus = false; - showProposalMapServerError = false; - showCrossSectionVirus = false; - showCrossSectionServerError = false; - showReclamationPlanVirus = false; - showReclamationPlanServerError = false; - showBuildingPlanVirus = false; - showBuildingPlanServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showCrossSectionHasVirusError = false; + showCrossSectionVirusScanFailedError = false; + showCrossSectionUnknownError = false; + showReclamationPlanHasVirusError = false; + showReclamationPlanVirusScanFailedError = false; + showReclamationPlanUnknownError = false; + showBuildingPlanHasVirusError = false; + showBuildingPlanVirusScanFailedError = false; + showBuildingPlanUnknownError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); @@ -192,23 +197,67 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachCrossSection(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); - this.showCrossSectionVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); + this.showCrossSectionHasVirusError = false; + this.showCrossSectionVirusScanFailedError = false; + this.showCrossSectionUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showCrossSectionUnknownError = + !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; + } } async attachReclamationPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); - this.showReclamationPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); + this.showReclamationPlanHasVirusError = false; + this.showReclamationPlanVirusScanFailedError = false; + this.showReclamationPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReclamationPlanUnknownError = + !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; + } } async attachBuildingPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); - this.showBuildingPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); + this.showBuildingPlanHasVirusError = false; + this.showBuildingPlanVirusScanFailedError = false; + this.showBuildingPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showBuildingPlanUnknownError = + !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html index 24fcbed757..5340e6357b 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html @@ -224,12 +224,22 @@

    Proposal

    - + - - -
    #{{ i + 1 }} + {{ i + 1 }} + Type + Proposal Total Floor Area + Proposal Action + @@ -561,8 +579,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -588,8 +607,9 @@

    Proposal

    [showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showCrossSectionVirus" - [showServerError]="showCrossSectionServerError" + [showHasVirusError]="showCrossSectionHasVirusError" + [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" + [showUnknownError]="showCrossSectionUnknownError" > @@ -617,8 +637,9 @@

    Proposal

    [showErrors]="showErrors" [isRequired]="true" [allowMultiple]="true" - [showVirusError]="showReclamationPlanVirus" - [showServerError]="showReclamationPlanServerError" + [showHasVirusError]="showReclamationPlanHasVirusError" + [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" + [showUnknownError]="showReclamationPlanUnknownError" > @@ -637,8 +658,9 @@

    Proposal

    (deleteFile)="onDeleteFile($event)" (openFile)="openFile($event)" [showErrors]="showErrors" - [showVirusError]="showBuildingPlanVirus" - [showServerError]="showBuildingPlanServerError" + [showHasVirusError]="showBuildingPlanHasVirusError" + [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" + [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="true" [allowMultiple]="true" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts index ce52c4f405..2e24426d7e 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts @@ -26,6 +26,7 @@ import { MOBILE_BREAKPOINT } from '../../../../../shared/utils/breakpoints'; import { AddStructureDialogComponent } from '../../../../../features/notice-of-intents/edit-submission/additional-information/add-structure-dialog/add-structure-dialog.component'; import { ProposedStructure } from '../../../../../services/notice-of-intent-submission/notice-of-intent-submission.dto'; import { v4 } from 'uuid'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-roso-proposal', @@ -53,14 +54,18 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, reclamationPlan: ApplicationDocumentDto[] = []; buildingPlans: ApplicationDocumentDto[] = []; - showProposalMapVirus = false; - showProposalMapServerError = false; - showCrossSectionVirus = false; - showCrossSectionServerError = false; - showReclamationPlanVirus = false; - showReclamationPlanServerError = false; - showBuildingPlanVirus = false; - showBuildingPlanServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showCrossSectionHasVirusError = false; + showCrossSectionVirusScanFailedError = false; + showCrossSectionUnknownError = false; + showReclamationPlanHasVirusError = false; + showReclamationPlanVirusScanFailedError = false; + showReclamationPlanUnknownError = false; + showBuildingPlanHasVirusError = false; + showBuildingPlanVirusScanFailedError = false; + showBuildingPlanUnknownError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); @@ -189,23 +194,67 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachCrossSection(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); - this.showCrossSectionVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); + this.showCrossSectionHasVirusError = false; + this.showCrossSectionVirusScanFailedError = false; + this.showCrossSectionUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showCrossSectionUnknownError = + !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; + } } async attachReclamationPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); - this.showReclamationPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); + this.showReclamationPlanHasVirusError = false; + this.showReclamationPlanVirusScanFailedError = false; + this.showReclamationPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReclamationPlanUnknownError = + !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; + } } async attachBuildingPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); - this.showBuildingPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); + this.showBuildingPlanHasVirusError = false; + this.showBuildingPlanVirusScanFailedError = false; + this.showBuildingPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showBuildingPlanUnknownError = + !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html index 345b1bfd60..b21db024e0 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html @@ -215,8 +215,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" >
    @@ -241,7 +242,7 @@

    Proposal

    Yes @@ -249,7 +250,7 @@

    Proposal

    No @@ -272,8 +273,9 @@

    Proposal

    [isRequired]="isHomeSiteSeverance.getRawValue() !== 'true'" [allowMultiple]="true" [disabled]="isHomeSiteSeverance.getRawValue() !== 'true'" - [showVirusError]="showHomesiteSeveranceVirus" - [showServerError]="showHomesiteSeveranceServerError" + [showHasVirusError]="showHomesiteSeveranceHasVirusError" + [showVirusScanFailedError]="showHomesiteSeveranceVirusScanFailedError" + [showUnknownError]="showHomesiteSeveranceUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts index 2e2c973c73..89287b2940 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts @@ -17,6 +17,7 @@ import { DOCUMENT_TYPE } from '../../../../../shared/dto/document.dto'; import { FileHandle } from '../../../../../shared/file-drag-drop/drag-drop.directive'; import { EditApplicationSteps } from '../../edit-submission.component'; import { FilesStepComponent } from '../../files-step.partial'; +import { HttpErrorResponse } from '@angular/common/http'; type FormProposedLot = { type: 'Lot' | 'Road Dedication' | null; size: string | null }; @@ -31,10 +32,12 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit, homesiteSeverance: ApplicationDocumentDto[] = []; proposalMap: ApplicationDocumentDto[] = []; - showHomesiteSeveranceVirus = false; - showHomesiteSeveranceServerError = false; - showProposalMapVirus = false; - showProposalMapServerError = false; + showHomesiteSeveranceHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showHomesiteSeveranceUnknownError = false; + showProposalMapHasVirusError = false; + showHomesiteSeveranceVirusScanFailedError = false; + showProposalMapUnknownError = false; lotsProposed = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); @@ -64,7 +67,7 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit, private parcelService: ApplicationParcelService, applicationDocumentService: ApplicationDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(applicationDocumentService, dialog, toastService); } @@ -122,13 +125,35 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachHomesiteSeverance(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.HOMESITE_SEVERANCE); - this.showHomesiteSeveranceVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.HOMESITE_SEVERANCE); + this.showHomesiteSeveranceHasVirusError = false; + this.showHomesiteSeveranceVirusScanFailedError = false; + this.showHomesiteSeveranceUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHomesiteSeveranceHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showHomesiteSeveranceVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showHomesiteSeveranceUnknownError = + !this.showHomesiteSeveranceHasVirusError && !this.showHomesiteSeveranceVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html index aa95d2293b..3f33cf56c1 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html @@ -149,7 +149,7 @@

    Proposal

    [formControl]="allOwnersNotified" [ngClass]="{ 'parcel-checkbox': true, - 'error-outline': allOwnersNotified.invalid && (allOwnersNotified.dirty || allOwnersNotified.touched) + 'error-outline': allOwnersNotified.invalid && (allOwnersNotified.dirty || allOwnersNotified.touched), }" >I confirm that all affected property owners with land in the ALR have been notified. @@ -178,8 +178,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showServingNoticeVirus" - [showServerError]="showServingNoticeServerError" + [showHasVirusError]="showServingNoticeHasVirusError" + [showVirusScanFailedError]="showServingNoticeVirusScanFailedError" + [showUnknownError]="showServingNoticeUnknownError" data-testid="proof-of-serving-notice-filechooser" > @@ -194,8 +195,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" data-testid="proposal-map-filechooser" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts index f373b58ccb..e3a132464a 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts @@ -12,6 +12,7 @@ import { DOCUMENT_TYPE } from '../../../../../shared/dto/document.dto'; import { FileHandle } from '../../../../../shared/file-drag-drop/drag-drop.directive'; import { EditApplicationSteps } from '../../edit-submission.component'; import { FilesStepComponent } from '../../files-step.partial'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-tur-proposal', @@ -26,10 +27,12 @@ export class TurProposalComponent extends FilesStepComponent implements OnInit, servingNotice: ApplicationDocumentDto[] = []; proposalMap: ApplicationDocumentDto[] = []; - showServingNoticeVirus = false; - showServingNoticeServerError = false; - showProposalMapVirus = false; - showProposalMapServerError = false; + showServingNoticeHasVirusError = false; + showServingNoticeVirusScanFailedError = false; + showServingNoticeUnknownError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; purpose = new FormControl(null, [Validators.required]); outsideLands = new FormControl(null, [Validators.required]); @@ -53,7 +56,7 @@ export class TurProposalComponent extends FilesStepComponent implements OnInit, private applicationService: ApplicationSubmissionService, applicationDocumentService: ApplicationDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(applicationDocumentService, dialog, toastService); } @@ -86,13 +89,35 @@ export class TurProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachServinceNotice(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.SERVING_NOTICE); - this.showServingNoticeVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.SERVING_NOTICE); + this.showServingNoticeHasVirusError = false; + this.showServingNoticeVirusScanFailedError = false; + this.showServingNoticeUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showServingNoticeHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showServingNoticeVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showServingNoticeUnknownError = + !this.showServingNoticeHasVirusError && !this.showServingNoticeVirusScanFailedError; + } } async onSave() { diff --git a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html index a97fe26d46..2b9e002235 100644 --- a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html +++ b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html @@ -18,8 +18,9 @@

    Attachments

    (openFile)="openFile($event)" [isRequired]="true" [showErrors]="showErrors" - [showVirusError]="showResolutionVirusError" - [showServerError]="showResolutionServerError" + [showHasVirusError]="showResolutionHasVirusError" + [showVirusScanFailedError]="showResolutionVirusScanFailedError" + [showUnknownError]="showResolutionUnknownError" >
    @@ -32,8 +33,9 @@

    Attachments

    (openFile)="openFile($event)" [isRequired]="isAuthorized" [showErrors]="showErrors" - [showVirusError]="showStaffReportVirusError" - [showServerError]="showStaffReportServerError" + [showHasVirusError]="showStaffReportHasVirusError" + [showVirusScanFailedError]="showStaffReportVirusScanFailedError" + [showUnknownError]="showStaffReportUnknownError" >
    @@ -45,8 +47,9 @@

    Attachments

    (deleteFile)="deleteFile($event)" (openFile)="openFile($event)" [allowMultiple]="true" - [showVirusError]="showOtherVirusError" - [showServerError]="showOtherServerError" + [showHasVirusError]="showOtherHasVirusError" + [showVirusScanFailedError]="showOtherVirusScanFailedError" + [showUnknownError]="showOtherUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts index 6f017eaef5..e5f8cc7525 100644 --- a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts +++ b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts @@ -8,6 +8,7 @@ import { DOCUMENT_SOURCE, DOCUMENT_TYPE } from '../../../../shared/dto/document. import { FileHandle } from '../../../../shared/file-drag-drop/drag-drop.directive'; import { ReviewApplicationFngSteps, ReviewApplicationSteps } from '../review-submission.component'; import { openFileInline } from '../../../../shared/utils/file'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-review-attachments', @@ -32,17 +33,21 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { isAuthorized = false; showMandatoryUploads = false; hasCompletedPreviousSteps = false; - showResolutionVirusError = false; - showResolutionServerError = false; - showStaffReportVirusError = false; - showStaffReportServerError = false; - showOtherVirusError = false; - showOtherServerError = false; + + showResolutionHasVirusError = false; + showResolutionVirusScanFailedError = false; + showResolutionUnknownError = false; + showStaffReportHasVirusError = false; + showStaffReportVirusScanFailedError = false; + showStaffReportUnknownError = false; + showOtherHasVirusError = false; + showOtherVirusScanFailedError = false; + showOtherUnknownError = false; constructor( private applicationReviewService: ApplicationSubmissionReviewService, private applicationDocumentService: ApplicationDocumentService, - private toastService: ToastService + private toastService: ToastService, ) {} ngOnInit(): void { @@ -72,11 +77,11 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { this.$applicationDocuments.pipe(takeUntil(this.$destroy)).subscribe((documents) => { this.resolutionDocument = documents.filter( - (document) => document.type?.code === DOCUMENT_TYPE.RESOLUTION_DOCUMENT + (document) => document.type?.code === DOCUMENT_TYPE.RESOLUTION_DOCUMENT, ); this.staffReport = documents.filter((document) => document.type?.code === DOCUMENT_TYPE.STAFF_REPORT); this.otherAttachments = documents.filter( - (document) => document.type?.code === DOCUMENT_TYPE.OTHER && document.source === DOCUMENT_SOURCE.LFNG + (document) => document.type?.code === DOCUMENT_TYPE.OTHER && document.source === DOCUMENT_SOURCE.LFNG, ); }); } @@ -89,18 +94,49 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { } async attachStaffReport(fileHandle: FileHandle) { - const res = await this.attachFile(fileHandle, DOCUMENT_TYPE.STAFF_REPORT); - this.showStaffReportVirusError = !res; + try { + await this.attachFile(fileHandle, DOCUMENT_TYPE.STAFF_REPORT); + this.showStaffReportHasVirusError = false; + this.showStaffReportVirusScanFailedError = false; + this.showStaffReportUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showStaffReportHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showStaffReportVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showStaffReportUnknownError = + !this.showStaffReportHasVirusError && !this.showStaffReportVirusScanFailedError; + } } async attachResolutionDocument(fileHandle: FileHandle) { - const res = await this.attachFile(fileHandle, DOCUMENT_TYPE.RESOLUTION_DOCUMENT); - this.showResolutionVirusError = !res; + try { + await this.attachFile(fileHandle, DOCUMENT_TYPE.RESOLUTION_DOCUMENT); + this.showResolutionHasVirusError = false; + this.showResolutionVirusScanFailedError = false; + this.showResolutionUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showResolutionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showResolutionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showResolutionUnknownError = !this.showResolutionHasVirusError && !this.showResolutionVirusScanFailedError; + } } async attachOtherDocument(fileHandle: FileHandle) { - const res = await this.attachFile(fileHandle, DOCUMENT_TYPE.OTHER); - this.showOtherVirusError = !res; + try { + await this.attachFile(fileHandle, DOCUMENT_TYPE.OTHER); + this.showOtherHasVirusError = false; + this.showOtherVirusScanFailedError = false; + this.showOtherUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showOtherHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showOtherVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showOtherUnknownError = !this.showOtherHasVirusError && this.showOtherVirusScanFailedError; + } } private async attachFile(fileHandle: FileHandle, documentType: DOCUMENT_TYPE) { @@ -110,16 +146,16 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { this.fileId, fileHandle.file, documentType, - DOCUMENT_SOURCE.LFNG + DOCUMENT_SOURCE.LFNG, ); this.toastService.showSuccessToast('Document uploaded'); - } catch (e) { + } catch (err) { this.toastService.showErrorToast('Document upload failed'); - return false; + + throw err; } await this.loadApplicationDocuments(this.fileId); } - return true; } async deleteFile($event: ApplicationDocumentDto) { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html index 66badd1bee..1ed087fd69 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html @@ -40,7 +40,7 @@

    Additional Proposal Information

    [ngClass]="{ 'error-outline': isRemovingSoilForNewStructure.invalid && - (isRemovingSoilForNewStructure.dirty || isRemovingSoilForNewStructure.touched) + (isRemovingSoilForNewStructure.dirty || isRemovingSoilForNewStructure.touched), }" value="true" >Yes @@ -50,7 +50,7 @@

    Additional Proposal Information

    [ngClass]="{ 'error-outline': isRemovingSoilForNewStructure.invalid && - (isRemovingSoilForNewStructure.dirty || isRemovingSoilForNewStructure.touched) + (isRemovingSoilForNewStructure.dirty || isRemovingSoilForNewStructure.touched), }" value="false" >No @@ -68,7 +68,7 @@

    Additional Proposal Information

    Provide the total floor area (m2) for each of the proposed structure(s)
    - Additional Proposal Information [isReviewStep]="false" (removeClicked)="onStructureRemove(structure.id)" (editClicked)="onStructureEdit(structure.id)" - > + >
    - + - - - @@ -381,8 +402,9 @@

    Additional Proposal Information

    (deleteFile)="onDeleteFile($event)" (openFile)="openFile($event)" [showErrors]="showErrors" - [showVirusError]="showBuildingPlanVirus" - [showServerError]="showBuildingPlanServerError" + [showHasVirusError]="showBuildingPlanHasVirusError" + [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" + [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="confirmRemovalOfSoil" [allowMultiple]="true" [disabled]="!confirmRemovalOfSoil" diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts index 9cb0d04970..5f33175b6d 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts @@ -24,6 +24,7 @@ import { DeleteStructureConfirmationDialogComponent } from './delete-structure-c import { SoilRemovalConfirmationDialogComponent } from './soil-removal-confirmation-dialog/soil-removal-confirmation-dialog.component'; import { AddStructureDialogComponent } from './add-structure-dialog/add-structure-dialog.component'; import { MOBILE_BREAKPOINT } from '../../../../shared/utils/breakpoints'; +import { HttpErrorResponse } from '@angular/common/http'; export enum STRUCTURE_TYPES { FARM_STRUCTURE = 'Farm Structure', @@ -95,8 +96,9 @@ export class AdditionalInformationComponent extends FilesStepComponent implement typeCode: string = ''; confirmRemovalOfSoil = false; - showBuildingPlanVirus = false; - showBuildingPlanServerError = false; + showBuildingPlanHasVirusError = false; + showBuildingPlanVirusScanFailedError = false; + showBuildingPlanUnknownError = false; buildingPlans: NoticeOfIntentDocumentDto[] = []; proposedStructures: FormProposedStructure[] = []; @@ -196,8 +198,19 @@ export class AdditionalInformationComponent extends FilesStepComponent implement } async attachBuildingPlan(file: FileHandle) { - const attachmentSucceeded = await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); - this.showBuildingPlanVirus = !attachmentSucceeded; + try { + await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); + this.showBuildingPlanHasVirusError = false; + this.showBuildingPlanVirusScanFailedError = false; + this.showBuildingPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showBuildingPlanUnknownError = + !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; + } } prepareStructureSpecificTextInputs() { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 7243a693d3..1f1c471575 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -10,8 +10,9 @@

    {{ title }} optional attachment

    [uploadedFiles]="attachment" [showErrors]="showFileRequiredError" [isRequired]="true" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index d02391dfd1..686eb7d075 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -11,6 +11,7 @@ import { OtherAttachmentsComponent } from '../other-attachments.component'; import { NoticeOfIntentDocumentService } from '../../../../../services/notice-of-intent-document/notice-of-intent-document.service'; import { CodeService } from '../../../../../services/code/code.service'; import { ToastService } from '../../../../../services/toast/toast.service'; +import { HttpErrorResponse } from '@angular/common/http'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @@ -23,8 +24,9 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { isDirty = false; isFileDirty = false; isSaving = false; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; showFileRequiredError = false; title: string = ''; isEditing = false; @@ -144,9 +146,12 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { protected async add() { if (this.isFileDirty) { this.isSaving = true; - const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); - this.showVirusError = !res; - if (res) { + try { + await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + const documents = await this.noticeOfIntentDocumentService.getByFileId(this.data.fileId); if (documents) { const sortedDocuments = documents.sort((a, b) => { @@ -168,8 +173,17 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { } else { this.toastService.showErrorToast('Could not read attached documents'); } + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } } + this.isDirty = false; + this.isFileDirty = true; + this.isSaving = false; } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async onEdit() { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts index 09b6c7ac79..10f151a525 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts @@ -15,6 +15,7 @@ import { EditNoiSteps } from '../edit-submission.component'; import { FilesStepComponent } from '../files-step.partial'; import { OtherAttachmentsUploadDialogComponent } from './other-attachments-upload-dialog/other-attachments-upload-dialog.component'; import { MOBILE_BREAKPOINT } from '../../../../shared/utils/breakpoints'; +import { HttpErrorResponse } from '@angular/common/http'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @@ -33,14 +34,16 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI private isDirty = false; private documentCodes: DocumentTypeDto[] = []; - showVirusError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; isMobile = window.innerWidth <= MOBILE_BREAKPOINT; constructor( private codeService: CodeService, noticeOfIntentDocumentService: NoticeOfIntentDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(noticeOfIntentDocumentService, dialog, toastService); } @@ -69,8 +72,18 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI } async attachDocument(file: FileHandle) { - const res = await this.attachFile(file, null); - this.showVirusError = !res; + try { + await this.attachFile(file, null); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; + } } protected async save() { @@ -93,15 +106,17 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI onAddEditAttachment(attachment: NoticeOfIntentDocumentDto | undefined) { this.dialog .open(OtherAttachmentsUploadDialogComponent, { - width: this.isMobile? '90%' : '50%', + width: this.isMobile ? '90%' : '50%', data: { fileId: this.fileId, otherAttachmentsComponent: this, existingDocument: attachment, - } - }).afterClosed().subscribe(async res => { - await this.refreshFiles(); - }); + }, + }) + .afterClosed() + .subscribe(async (res) => { + await this.refreshFiles(); + }); } @HostListener('window:resize', ['$event']) diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html index 88e59043bc..37506f60c8 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html @@ -238,8 +238,9 @@ (beforeFileUploadOpened)="saveParcelProgress()" [showErrors]="showErrors" [isRequired]="isCertificateOfTitleRequired" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" [disabled]="parcelForm.controls.pid.disabled" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts index a31aceb7d9..9d348a44ea 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts @@ -22,6 +22,7 @@ import { scrollToElement } from '../../../../../shared/utils/scroll-helper'; import { RemoveFileConfirmationDialogComponent } from '../../../../applications/alcs-edit-submission/remove-file-confirmation-dialog/remove-file-confirmation-dialog.component'; import { ParcelEntryConfirmationDialogComponent } from './parcel-entry-confirmation-dialog/parcel-entry-confirmation-dialog.component'; import { MOBILE_BREAKPOINT } from '../../../../../shared/utils/breakpoints'; +import { HttpErrorResponse } from '@angular/common/http'; export interface ParcelEntryFormData { uuid: string; @@ -66,8 +67,9 @@ export class ParcelEntryComponent implements OnInit { searchBy = new FormControl(null); isCrownLand: boolean | null = null; isCertificateOfTitleRequired = true; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; isMobile = false; parcelType = new FormControl(null, [Validators.required]); @@ -313,13 +315,20 @@ export class ParcelEntryComponent implements OnInit { mappedFiles, ); this.toastService.showSuccessToast('Document uploaded'); - } catch (e) { - this.showVirusError = true; - this.toastService.showErrorToast('Document upload failed'); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; return; + } catch (err) { + this.toastService.showErrorToast('Document upload failed'); + + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } } - this.showVirusError = false; } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async deleteFile($event: NoticeOfIntentDocumentDto) { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html index c73e37f84d..58959a7fa8 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html @@ -84,7 +84,7 @@

    Primary Contact

    Phone Number:
    -
    {{ phoneNumber.value ?? '' | mask : '(000) 000-0000' }}
    +
    {{ phoneNumber.value ?? '' | mask: '(000) 000-0000' }}
    Email:
    @@ -218,8 +218,9 @@

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="needsAuthorizationLetter" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" >

    diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts index 67e6de3976..7dc914879b 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts @@ -23,6 +23,7 @@ import { CrownOwnerDialogComponent } from '../../../../shared/owner-dialogs/crow import { scrollToElement } from '../../../../shared/utils/scroll-helper'; import { MatButtonToggleChange } from '@angular/material/button-toggle'; import { strictEmailValidator } from '../../../../shared/validators/email-validator'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-primary-contact', @@ -37,8 +38,9 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni files: (NoticeOfIntentDocumentDto & { errorMessage?: string })[] = []; needsAuthorizationLetter = false; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; selectedThirdPartyAgent: boolean | null = false; selectedLocalGovernment = false; _selectedOwnerUuid: string | undefined = undefined; @@ -105,8 +107,19 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni } async attachAuthorizationLetter(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.AUTHORIZATION_LETTER); - this.showVirusError = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.AUTHORIZATION_LETTER); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showUnknownError = + !this.showHasVirusError && !this.showVirusScanFailedError && !this.showVirusScanFailedError; + } } set selectedOwnerUuid(value: string | undefined) { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html index 33de034b54..2607514ee6 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html @@ -40,7 +40,7 @@

    Proposal

    Yes @@ -48,7 +48,7 @@

    Proposal

    No @@ -277,8 +277,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -294,7 +295,7 @@

    Proposal

    Yes @@ -302,7 +303,7 @@

    Proposal

    No @@ -326,7 +327,7 @@

    Proposal

    class="toggle-button" [ngClass]="{ 'error-outline': - isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched) + isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched), }" value="true" >Yes @@ -335,7 +336,7 @@

    Proposal

    class="toggle-button" [ngClass]="{ 'error-outline': - isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched) + isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched), }" value="false" >No @@ -373,8 +374,9 @@

    Proposal

    [isRequired]="true" [allowMultiple]="true" [disabled]="!allowMiningUploads" - [showVirusError]="showCrossSectionVirus" - [showServerError]="showCrossSectionServerError" + [showHasVirusError]="showCrossSectionHasVirusError" + [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" + [showUnknownError]="showCrossSectionUnknownError" >
    @@ -402,8 +404,9 @@

    Proposal

    [isRequired]="true" [allowMultiple]="true" [disabled]="!allowMiningUploads" - [showVirusError]="showReclamationPlanVirus" - [showServerError]="showReclamationPlanServerError" + [showHasVirusError]="showReclamationPlanHasVirusError" + [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" + [showUnknownError]="showReclamationPlanUnknownError" >
    @@ -422,7 +425,7 @@

    Proposal

    Yes @@ -430,7 +433,7 @@

    Proposal

    No @@ -467,8 +470,9 @@

    Proposal

    [isRequired]="true" [disabled]="!requiresNoticeOfWork" [allowMultiple]="true" - [showVirusError]="showNoticeOfWorkVirus" - [showServerError]="showNoticeOfWorkServerError" + [showHasVirusError]="showNoticeOfWorkHasVirusError" + [showVirusScanFailedError]="showNoticeOfWorkVirusScanFailedError" + [showUnknownError]="showNoticeOfWorkUnknownError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts index 769fd39a04..2651531e7b 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts @@ -16,6 +16,7 @@ import { parseStringToBoolean } from '../../../../../shared/utils/string-helper' import { SoilTableData } from '../../../../../shared/soil-table/soil-table.component'; import { EditNoiSteps } from '../../edit-submission.component'; import { FilesStepComponent } from '../../files-step.partial'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-pfrs-proposal', @@ -34,14 +35,18 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, allowMiningUploads = false; requiresNoticeOfWork = false; - showProposalMapVirus = false; - showProposalMapServerError = false; - showCrossSectionVirus = false; - showCrossSectionServerError = false; - showReclamationPlanVirus = false; - showReclamationPlanServerError = false; - showNoticeOfWorkVirus = false; - showNoticeOfWorkServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showCrossSectionHasVirusError = false; + showCrossSectionVirusScanFailedError = false; + showCrossSectionUnknownError = false; + showReclamationPlanHasVirusError = false; + showReclamationPlanVirusScanFailedError = false; + showReclamationPlanUnknownError = false; + showNoticeOfWorkHasVirusError = false; + showNoticeOfWorkVirusScanFailedError = false; + showNoticeOfWorkUnknownError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; @@ -85,7 +90,7 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, private noticeOfIntentSubmissionService: NoticeOfIntentSubmissionService, noticeOfIntentDocumentService: NoticeOfIntentDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(noticeOfIntentDocumentService, dialog, toastService); } @@ -170,23 +175,67 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachCrossSection(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); - this.showCrossSectionVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); + this.showCrossSectionHasVirusError = false; + this.showCrossSectionVirusScanFailedError = false; + this.showCrossSectionUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showCrossSectionUnknownError = + !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; + } } async attachReclamationPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); - this.showReclamationPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); + this.showReclamationPlanHasVirusError = false; + this.showReclamationPlanVirusScanFailedError = false; + this.showReclamationPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReclamationPlanUnknownError = + !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; + } } async attachNoticeOfWork(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); - this.showNoticeOfWorkVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); + this.showNoticeOfWorkHasVirusError = false; + this.showNoticeOfWorkVirusScanFailedError = false; + this.showNoticeOfWorkUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showNoticeOfWorkHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showNoticeOfWorkVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showNoticeOfWorkUnknownError = + !this.showNoticeOfWorkHasVirusError && !this.showNoticeOfWorkVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html index b9877f0e5a..ea08764d3a 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html @@ -40,7 +40,7 @@

    Proposal

    Yes @@ -48,7 +48,7 @@

    Proposal

    No @@ -195,8 +195,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -212,7 +213,7 @@

    Proposal

    Yes @@ -220,7 +221,7 @@

    Proposal

    No @@ -251,8 +252,9 @@

    Proposal

    [isRequired]="true" [allowMultiple]="true" [disabled]="!allowMiningUploads" - [showVirusError]="showCrossSectionVirus" - [showServerError]="showCrossSectionServerError" + [showHasVirusError]="showCrossSectionHasVirusError" + [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" + [showUnknownError]="showCrossSectionUnknownError" >
    @@ -280,8 +282,9 @@

    Proposal

    [isRequired]="true" [allowMultiple]="true" [disabled]="!allowMiningUploads" - [showVirusError]="showReclamationPlanVirus" - [showServerError]="showReclamationPlanServerError" + [showHasVirusError]="showReclamationPlanHasVirusError" + [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" + [showUnknownError]="showReclamationPlanUnknownError" >
    diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts index b657d97cfe..c6394ce3db 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts @@ -15,6 +15,7 @@ import { parseStringToBoolean } from '../../../../../shared/utils/string-helper' import { SoilTableData } from '../../../../../shared/soil-table/soil-table.component'; import { EditNoiSteps } from '../../edit-submission.component'; import { FilesStepComponent } from '../../files-step.partial'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-pofo-proposal', @@ -27,12 +28,15 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, DOCUMENT = DOCUMENT_TYPE; allowMiningUploads = false; - showProposalMapVirus = false; - showProposalMapServerError = false; - showCrossSectionVirus = false; - showCrossSectionServerError = false; - showReclamationPlanVirus = false; - showReclamationPlanServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showCrossSectionHasVirusError = false; + showCrossSectionVirusScanFailedError = false; + showCrossSectionUnknownError = false; + showReclamationPlanHasVirusError = false; + showReclamationPlanVirusScanFailedError = false; + showReclamationPlanUnknownError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; @@ -120,18 +124,49 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = !this.showProposalMapHasVirusError; + } } async attachCrossSection(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); - this.showCrossSectionVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); + this.showCrossSectionHasVirusError = false; + this.showCrossSectionVirusScanFailedError = false; + this.showCrossSectionUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showCrossSectionUnknownError = + !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; + } } async attachReclamationPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); - this.showReclamationPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); + this.showReclamationPlanHasVirusError = false; + this.showReclamationPlanVirusScanFailedError = false; + this.showReclamationPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReclamationPlanUnknownError = !this.showReclamationPlanHasVirusError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html index db79c717dd..abf78b8d13 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html @@ -40,7 +40,7 @@

    Proposal

    Yes @@ -48,7 +48,7 @@

    Proposal

    No @@ -180,8 +180,9 @@

    Proposal

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showProposalMapVirus" - [showServerError]="showProposalMapServerError" + [showHasVirusError]="showProposalMapHasVirusError" + [showVirusScanFailedError]="showProposalMapVirusScanFailedError" + [showUnknownError]="showProposalMapUnknownError" > @@ -200,7 +201,7 @@

    Proposal

    class="toggle-button" [ngClass]="{ 'error-outline': - isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched) + isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched), }" value="true" >Yes @@ -209,7 +210,7 @@

    Proposal

    class="toggle-button" [ngClass]="{ 'error-outline': - isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched) + isExtractionOrMining.invalid && (isExtractionOrMining.dirty || isExtractionOrMining.touched), }" value="false" >No @@ -240,8 +241,9 @@

    Proposal

    [isRequired]="true" [allowMultiple]="true" [disabled]="!allowMiningUploads" - [showVirusError]="showCrossSectionVirus" - [showServerError]="showCrossSectionServerError" + [showHasVirusError]="showCrossSectionHasVirusError" + [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" + [showUnknownError]="showCrossSectionUnknownError" >
    @@ -269,8 +271,9 @@

    Proposal

    [isRequired]="true" [allowMultiple]="true" [disabled]="!allowMiningUploads" - [showVirusError]="showReclamationPlanVirus" - [showServerError]="showReclamationPlanServerError" + [showHasVirusError]="showReclamationPlanHasVirusError" + [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" + [showUnknownError]="showReclamationPlanUnknownError" >
    @@ -289,7 +292,7 @@

    Proposal

    Yes @@ -297,7 +300,7 @@

    Proposal

    No @@ -327,8 +330,9 @@

    Proposal

    [isRequired]="true" [disabled]="!requiresNoticeOfWork" [allowMultiple]="true" - [showVirusError]="showNoticeOfWorkVirus" - [showServerError]="showNoticeOfWorkServerError" + [showHasVirusError]="showNoticeOfWorkHasVirusError" + [showVirusScanFailedError]="showNoticeOfWorkVirusScanFailedError" + [showUnknownError]="showNoticeOfWorkUnknownError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts index ce326de054..2c90215386 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts @@ -15,6 +15,7 @@ import { parseStringToBoolean } from '../../../../../shared/utils/string-helper' import { SoilTableData } from '../../../../../shared/soil-table/soil-table.component'; import { EditNoiSteps } from '../../edit-submission.component'; import { FilesStepComponent } from '../../files-step.partial'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-roso-proposal', @@ -28,14 +29,18 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, allowMiningUploads = false; requiresNoticeOfWork = false; - showProposalMapVirus = false; - showProposalMapServerError = false; - showCrossSectionVirus = false; - showCrossSectionServerError = false; - showReclamationPlanVirus = false; - showReclamationPlanServerError = false; - showNoticeOfWorkVirus = false; - showNoticeOfWorkServerError = false; + showProposalMapHasVirusError = false; + showProposalMapVirusScanFailedError = false; + showProposalMapUnknownError = false; + showCrossSectionHasVirusError = false; + showCrossSectionVirusScanFailedError = false; + showCrossSectionUnknownError = false; + showReclamationPlanHasVirusError = false; + showReclamationPlanVirusScanFailedError = false; + showReclamationPlanUnknownError = false; + showNoticeOfWorkHasVirusError = false; + showNoticeOfWorkVirusScanFailedError = false; + showNoticeOfWorkUnknownError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; @@ -70,7 +75,7 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, private noticeOfIntentSubmissionService: NoticeOfIntentSubmissionService, noticeOfIntentDocumentService: NoticeOfIntentDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(noticeOfIntentDocumentService, dialog, toastService); } @@ -136,23 +141,67 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, } async attachProposalMap(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); - this.showProposalMapVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); + this.showProposalMapHasVirusError = false; + this.showProposalMapVirusScanFailedError = false; + this.showProposalMapUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showProposalMapUnknownError = + !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; + } } async attachCrossSection(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); - this.showCrossSectionVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); + this.showCrossSectionHasVirusError = false; + this.showCrossSectionVirusScanFailedError = false; + this.showCrossSectionUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showCrossSectionUnknownError = + !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; + } } async attachReclamationPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); - this.showReclamationPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); + this.showReclamationPlanHasVirusError = false; + this.showReclamationPlanVirusScanFailedError = false; + this.showReclamationPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showReclamationPlanUnknownError = + !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; + } } async attachNoticeOfWork(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); - this.showNoticeOfWorkVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); + this.showNoticeOfWorkHasVirusError = false; + this.showNoticeOfWorkVirusScanFailedError = false; + this.showNoticeOfWorkUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showNoticeOfWorkHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showNoticeOfWorkVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showNoticeOfWorkUnknownError = + !this.showNoticeOfWorkHasVirusError && !this.showNoticeOfWorkVirusScanFailedError; + } } protected async save() { diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index d4553a158b..94a807d5f4 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -10,12 +10,13 @@

    {{ title }} optional attachment

    [uploadedFiles]="attachment" [showErrors]="showFileRequiredError" [isRequired]="true" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" > - + warning A virus was detected in the file. Choose another file and try again.
    diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index cb9e0e1093..b261fb6c5d 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -11,6 +11,7 @@ import { OtherAttachmentsComponent } from '../other-attachments.component'; import { NotificationDocumentService } from '../../../../../services/notification-document/notification-document.service'; import { CodeService } from '../../../../../services/code/code.service'; import { ToastService } from '../../../../../services/toast/toast.service'; +import { HttpErrorResponse } from '@angular/common/http'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @@ -23,8 +24,9 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { isDirty = false; isFileDirty = false; isSaving = false; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; showFileRequiredError = false; title: string = ''; isEditing = false; @@ -146,9 +148,12 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { protected async add() { if (this.isFileDirty) { this.isSaving = true; - const res = await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); - this.showVirusError = !res; - if (res) { + try { + await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + const documents = await this.notificationDocumentService.getByFileId(this.data.fileId); if (documents) { const sortedDocuments = documents.sort((a, b) => { @@ -170,11 +175,17 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { } else { this.toastService.showErrorToast('Could not read attached documents'); } + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } } this.isDirty = false; this.isFileDirty = true; this.isSaving = false; } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async onEdit() { diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts index 23a7abf237..3d9eae8092 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts @@ -17,6 +17,7 @@ import { EditNotificationSteps } from '../edit-submission.component'; import { FilesStepComponent } from '../files-step.partial'; import { OtherAttachmentsUploadDialogComponent } from './other-attachments-upload-dialog/other-attachments-upload-dialog.component'; import { MOBILE_BREAKPOINT } from '../../../../shared/utils/breakpoints'; +import { HttpErrorResponse } from '@angular/common/http'; const USER_CONTROLLED_TYPES = [DOCUMENT_TYPE.PHOTOGRAPH, DOCUMENT_TYPE.PROFESSIONAL_REPORT, DOCUMENT_TYPE.OTHER]; @@ -33,7 +34,9 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI otherFiles: NotificationDocumentDto[] = []; private isDirty = false; - showVirusError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; isMobile = window.innerWidth <= MOBILE_BREAKPOINT; private documentCodes: DocumentTypeDto[] = []; @@ -42,7 +45,7 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI private codeService: CodeService, toastService: ToastService, notificationDocumentService: NotificationDocumentService, - dialog: MatDialog + dialog: MatDialog, ) { super(notificationDocumentService, dialog, toastService); } @@ -71,8 +74,18 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI } async attachDocument(file: FileHandle) { - const res = await this.attachFile(file, null); - this.showVirusError = !res; + try { + await this.attachFile(file, null); + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; + } } protected async save() { @@ -95,15 +108,17 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI onAddEditAttachment(attachment: NotificationDocumentDto | undefined) { this.dialog .open(OtherAttachmentsUploadDialogComponent, { - width: this.isMobile? '90%' : '50%', + width: this.isMobile ? '90%' : '50%', data: { fileId: this.fileId, otherAttachmentsComponent: this, existingDocument: attachment, - } - }).afterClosed().subscribe(async res => { - await this.refreshFiles(); - }); + }, + }) + .afterClosed() + .subscribe(async (res) => { + await this.refreshFiles(); + }); } @HostListener('window:resize', ['$event']) diff --git a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html index 889a803d9c..93eaf9707e 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html +++ b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html @@ -77,8 +77,9 @@

    Purpose of SRW

    (openFile)="openFile($event)" [showErrors]="showErrors" [isRequired]="true" - [showVirusError]="showSRWTermsVirus" - [showServerError]="showSRWTermsVirus" + [showHasVirusError]="showSRWTermsHasVirusError" + [showVirusScanFailedError]="showSRWTermsVirusScanFailedError" + [showUnknownError]="showSRWTermsHasVirusError" > @@ -94,7 +95,7 @@

    Purpose of SRW

    Yes @@ -102,7 +103,7 @@

    Purpose of SRW

    No @@ -123,8 +124,9 @@

    Purpose of SRW

    [isRequired]="surveyPlans.length === 0" [disabled]="!allowSurveyPlanUploads" [allowMultiple]="true" - [showVirusError]="showSurveyPlanVirus" - [showServerError]="showSurveyPlanServerError" + [showHasVirusError]="showSurveyPlanHasVirusError" + [showVirusScanFailedError]="showSurveyPlanVirusScanFailedError" + [showUnknownError]="showSurveyPlanUnknownError" > diff --git a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts index 9f85926c04..c54107a12a 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts @@ -18,6 +18,7 @@ import { parseStringToBoolean } from '../../../../shared/utils/string-helper'; import { EditNotificationSteps } from '../edit-submission.component'; import { FilesStepComponent } from '../files-step.partial'; import { ChangeSurveyPlanConfirmationDialogComponent } from './change-survey-plan-confirmation-dialog/change-survey-plan-confirmation-dialog.component'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-proposal', @@ -48,17 +49,19 @@ export class ProposalComponent extends FilesStepComponent implements OnInit, OnD private submissionUuid = ''; private isDirty = false; surveyForm = new FormGroup({} as any); - showSRWTermsVirus = false; - showSRWTermsServerError = false; - showSurveyPlanVirus = false; - showSurveyPlanServerError = false; + showSRWTermsHasVirusError = false; + showSRWTermsVirusScanFailedError = false; + showSRWTermsUnknownError = false; + showSurveyPlanHasVirusError = false; + showSurveyPlanVirusScanFailedError = false; + showSurveyPlanUnknownError = false; constructor( private router: Router, private notificationSubmissionService: NotificationSubmissionService, notificationDocumentService: NotificationDocumentService, dialog: MatDialog, - toastService: ToastService + toastService: ToastService, ) { super(notificationDocumentService, dialog, toastService); } @@ -100,13 +103,33 @@ export class ProposalComponent extends FilesStepComponent implements OnInit, OnD } async attachSRWTerms(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.SRW_TERMS); - this.showSRWTermsVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.SRW_TERMS); + this.showSRWTermsHasVirusError = false; + this.showSRWTermsVirusScanFailedError = false; + this.showSRWTermsUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showSRWTermsHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showSRWTermsVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showSRWTermsUnknownError = !this.showSRWTermsHasVirusError && !this.showSRWTermsVirusScanFailedError; + } } async attachSurveyPlan(file: FileHandle) { - const res = await this.attachFile(file, DOCUMENT_TYPE.SURVEY_PLAN); - this.showSurveyPlanVirus = !res; + try { + await this.attachFile(file, DOCUMENT_TYPE.SURVEY_PLAN); + this.showSurveyPlanHasVirusError = false; + this.showSurveyPlanVirusScanFailedError = false; + this.showSurveyPlanUnknownError = false; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showSurveyPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showSurveyPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } + this.showSurveyPlanUnknownError = !this.showSurveyPlanHasVirusError && !this.showSurveyPlanVirusScanFailedError; + } } async onSave() { diff --git a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html index c5cd828a2e..175c4a3578 100644 --- a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html +++ b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html @@ -28,7 +28,11 @@ [ngClass]="{ 'desktop-file-drag-drop': true, 'error-outline': - !disabled && ((isRequired && showErrors && !uploadedFiles.length) || showVirusError || showServerError), + !disabled && + ((isRequired && showErrors && !uploadedFiles.length) || + showHasVirusError || + showVirusScanFailedError || + showUnknownError), disabled: disabled, }" dragDropFile @@ -56,10 +60,13 @@ This file upload is required - + A virus was detected in the file. Choose another file and try again. - + + A problem occurred while scanning for viruses. Please try again. + + There was a problem uploading the file. Please try again. Maximum file size: 100 MB diff --git a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts index a7750e122b..f695674846 100644 --- a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts +++ b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts @@ -19,8 +19,9 @@ export class FileDragDropComponent implements OnInit { @Input() uploadedFiles: (ApplicationDocumentDto & { errorMessage?: string })[] = []; @Input() isRequired = false; @Input() showErrors = false; - @Input() showVirusError = false; - @Input() showServerError = false; + @Input() showHasVirusError = false; + @Input() showVirusScanFailedError = false; + @Input() showUnknownError = false; private uploadClicked = false; diff --git a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html index afc2c8efcc..bf96df55fc 100644 --- a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html +++ b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html @@ -46,8 +46,9 @@
    id="fileUpload" [showErrors]="showFileErrors" [isRequired]="true" - [showVirusError]="showVirusError" - [showServerError]="showServerError" + [showHasVirusError]="showHasVirusError" + [showVirusScanFailedError]="showVirusScanFailedError" + [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts index 3f4b519280..c9ee9d3a12 100644 --- a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts +++ b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts @@ -22,6 +22,7 @@ import { FileHandle } from '../../file-drag-drop/drag-drop.directive'; import { openFileInline } from '../../utils/file'; import { strictEmailValidator } from '../../validators/email-validator'; import { ToastService } from '../../../services/toast/toast.service'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-owner-dialog', @@ -39,8 +40,9 @@ export class OwnerDialogComponent { corporateSummary = new FormControl(null); isEdit = false; - showVirusError = false; - showServerError = false; + showHasVirusError = false; + showVirusScanFailedError = false; + showUnknownError = false; existingUuid: string | undefined; files: ApplicationDocumentDto[] = []; showFileErrors = false; @@ -101,7 +103,7 @@ export class OwnerDialogComponent { this.corporateSummary.setValidators([Validators.required]); } else { this.organizationName.setValidators([]); - this.corporateSummary.setValidators([]); + this.corporateSummary.setValidators([]); } this.corporateSummary.updateValueAndValidity(); this.organizationName.updateValueAndValidity(); @@ -184,7 +186,7 @@ export class OwnerDialogComponent { let document; if (this.pendingFile) { document = await this.uploadPendingFile(this.pendingFile); - } else { + } else { document = this.type.value === OWNER_TYPE.ORGANIZATION ? this.data.existingOwner?.corporateSummary : null; } @@ -217,7 +219,7 @@ export class OwnerDialogComponent { this.corporateSummary.setValue('pending'); const corporateSummaryType = this.documentCodes.find((code) => code.code === DOCUMENT_TYPE.CORPORATE_SUMMARY); if (corporateSummaryType) { - this.showVirusError = false; + this.showHasVirusError = false; this.files = [ { type: corporateSummaryType, @@ -270,21 +272,27 @@ export class OwnerDialogComponent { } private async uploadPendingFile(file?: File) { - let documentUuid; if (file) { try { - documentUuid = await this.data.ownerService.uploadCorporateSummary(this.data.fileId, file); + const documentUuid = await this.data.ownerService.uploadCorporateSummary(this.data.fileId, file); this.toastService.showSuccessToast('Document uploaded'); - } catch (e) { - this.showVirusError = true; + this.showHasVirusError = false; + this.showVirusScanFailedError = false; + this.showUnknownError = false; + return documentUuid; + } catch (err) { + if (err instanceof HttpErrorResponse) { + this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; + this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; + } this.pendingFile = undefined; this.corporateSummary.setValue(null); this.files = []; this.toastService.showErrorToast('Document upload failed'); - return; } } - return documentUuid; + this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; + return; } private async loadDocumentCodes() { From 14e2ed22150dded943f1c609e2c40c281f6e04ef Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:38:20 -0800 Subject: [PATCH 27/30] Fix missing doc type -> vis map keys throwing error --- .../document-upload-dialog.component.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts index 41442c1319..c3d28fe017 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.ts @@ -80,7 +80,7 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { selectableParcels?: SelectableParcelDto[]; selectableOwners?: SelectableOwnerDto[]; allowedVisibilityFlags?: ('A' | 'C' | 'G' | 'P')[]; - documentTypeToVisibilityGroupsMap: Record; + documentTypeToVisibilityGroupsMap?: Record; }, protected dialog: MatDialogRef, private toastService: ToastService, @@ -289,13 +289,15 @@ export class DocumentUploadDialogComponent implements OnInit, OnDestroy { return; } - for (const visibilityGroup of this.data.documentTypeToVisibilityGroupsMap[$event.code]) { - if (visibilityGroup === VisibilityGroup.INTERNAL) { - this.visibleToInternal.setValue(true); - } + if (this.data.documentTypeToVisibilityGroupsMap && this.data.documentTypeToVisibilityGroupsMap[$event.code]) { + for (const visibilityGroup of this.data.documentTypeToVisibilityGroupsMap[$event.code]) { + if (visibilityGroup === VisibilityGroup.INTERNAL) { + this.visibleToInternal.setValue(true); + } - if (visibilityGroup === VisibilityGroup.PUBLIC) { - this.visibleToPublic.setValue(true); + if (visibilityGroup === VisibilityGroup.PUBLIC) { + this.visibleToPublic.setValue(true); + } } } From ee8f2fc321a7806b205ab26f8ad083a7fb85ac94 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 12:05:06 -0800 Subject: [PATCH 28/30] Remove unneeded unknown error text --- ...r-attachments-upload-dialog.component.html | 1 - ...her-attachments-upload-dialog.component.ts | 4 ---- .../other-attachments.component.ts | 3 --- .../parcel-entry/parcel-entry.component.html | 1 - .../parcel-entry/parcel-entry.component.ts | 3 --- .../primary-contact.component.html | 1 - .../primary-contact.component.ts | 3 --- .../cove-proposal.component.html | 2 -- .../cove-proposal/cove-proposal.component.ts | 8 -------- .../excl-proposal.component.html | 4 ---- .../excl-proposal/excl-proposal.component.ts | 16 --------------- .../incl-proposal.component.html | 4 ---- .../incl-proposal/incl-proposal.component.ts | 16 --------------- .../naru-proposal.component.html | 2 -- .../naru-proposal/naru-proposal.component.ts | 8 -------- .../nfu-proposal/nfu-proposal.component.html | 1 - .../nfu-proposal/nfu-proposal.component.ts | 4 ---- .../pfrs-proposal.component.html | 5 ----- .../pfrs-proposal/pfrs-proposal.component.ts | 20 ------------------- .../pofo-proposal.component.html | 4 ---- .../pofo-proposal/pofo-proposal.component.ts | 16 --------------- .../roso-proposal.component.html | 4 ---- .../roso-proposal/roso-proposal.component.ts | 16 --------------- .../subd-proposal.component.html | 2 -- .../subd-proposal/subd-proposal.component.ts | 8 -------- .../tur-proposal/tur-proposal.component.html | 2 -- .../tur-proposal/tur-proposal.component.ts | 8 -------- .../review-attachments.component.html | 3 --- .../review-attachments.component.ts | 10 ---------- .../additional-information.component.html | 1 - .../additional-information.component.ts | 4 ---- ...r-attachments-upload-dialog.component.html | 1 - ...her-attachments-upload-dialog.component.ts | 3 --- .../other-attachments.component.ts | 3 --- .../parcel-entry/parcel-entry.component.html | 1 - .../parcel-entry/parcel-entry.component.ts | 3 --- .../primary-contact.component.html | 1 - .../primary-contact.component.ts | 4 ---- .../pfrs/pfrs-proposal.component.html | 4 ---- .../proposal/pfrs/pfrs-proposal.component.ts | 16 --------------- .../pofo/pofo-proposal.component.html | 3 --- .../proposal/pofo/pofo-proposal.component.ts | 10 ---------- .../roso/roso-proposal.component.html | 4 ---- .../proposal/roso/roso-proposal.component.ts | 16 --------------- ...r-attachments-upload-dialog.component.html | 1 - ...her-attachments-upload-dialog.component.ts | 3 --- .../other-attachments.component.ts | 3 --- .../proposal/proposal.component.html | 2 -- .../proposal/proposal.component.ts | 6 ------ .../file-drag-drop.component.html | 8 +------- .../file-drag-drop.component.ts | 1 - .../owner-dialog/owner-dialog.component.html | 1 - .../owner-dialog/owner-dialog.component.ts | 3 --- 53 files changed, 1 insertion(+), 280 deletions(-) diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 1f1c471575..a915d3aa02 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -12,7 +12,6 @@

    {{ title }} optional attachment

    [isRequired]="true" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index c07bac2a9a..451db086cf 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -27,7 +27,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { isSaving = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; showFileRequiredError = false; title: string = ''; isEditing = false; @@ -151,7 +150,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; const documents = await this.applicationDcoumentService.getByFileId(this.data.fileId); @@ -174,7 +172,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { this.dialogRef.close(); } else { this.toastService.showErrorToast('Could not read attached documents'); - this.showUnknownError = true; } } catch (err) { if (err instanceof HttpErrorResponse) { @@ -186,7 +183,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { this.isFileDirty = true; this.isSaving = false; } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async onEdit() { diff --git a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts index b3d0a788e1..e6ca352239 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/other-attachments/other-attachments.component.ts @@ -36,7 +36,6 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI private isDirty = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; isMobile = window.innerWidth <= MOBILE_BREAKPOINT; form = new FormGroup({} as any); @@ -81,13 +80,11 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI await this.attachFile(file, null); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showUnknownError = !this.showHasVirusError || !this.showVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html index 81a747f01b..0d225d5bb8 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.html @@ -243,7 +243,6 @@ [isRequired]="isCertificateOfTitleRequired" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" [disabled]="parcelForm.controls.pid.disabled" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts index 13fe34df94..ebadf41620 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/parcel-details/parcel-entry/parcel-entry.component.ts @@ -60,7 +60,6 @@ export class ParcelEntryComponent implements OnInit { showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; @Output() private onFormGroupChange = new EventEmitter>(); @Output() private onSaveProgress = new EventEmitter(); @@ -314,7 +313,6 @@ export class ParcelEntryComponent implements OnInit { this.toastService.showSuccessToast('Document uploaded'); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; return; } catch (err) { this.toastService.showErrorToast('Document upload failed'); @@ -325,7 +323,6 @@ export class ParcelEntryComponent implements OnInit { } } } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async deleteFile($event: ApplicationDocumentDto) { diff --git a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html index 9709f936b6..8016f86310 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.html @@ -219,7 +219,6 @@

    [isRequired]="needsAuthorizationLetter" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts index a568f11e23..1207be60b2 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/primary-contact/primary-contact.component.ts @@ -46,7 +46,6 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni isDirty = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; hasCrownParcels = false; ownersList = new FormControl(null, [Validators.required]); @@ -109,13 +108,11 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni await this.attachFile(file, DOCUMENT_TYPE.AUTHORIZATION_LETTER); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html index aec5f2dc34..04928a197d 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.html @@ -188,7 +188,6 @@

    Proposal

    [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" >
    @@ -234,7 +233,6 @@

    Proposal

    [disabled]="!canUploadDraft" [showHasVirusError]="showDraftCovenantHasVirusError" [showVirusScanFailedError]="showDraftCovenantVirusScanFailedError" - [showUnknownError]="showDraftCovenantUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts index 635574f8f6..2f97b0e10b 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/cove-proposal/cove-proposal.component.ts @@ -52,11 +52,9 @@ export class CoveProposalComponent extends FilesStepComponent implements OnInit, proposalMap: ApplicationDocumentDto[] = []; showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; draftCovenant: ApplicationDocumentDto[] = []; showDraftCovenantHasVirusError = false; showDraftCovenantVirusScanFailedError = false; - showDraftCovenantUnknownError = false; isMobile = false; visibleCount = VISIBLE_COUNT_INCREMENT; @@ -136,14 +134,11 @@ export class CoveProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -152,14 +147,11 @@ export class CoveProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.SRW_TERMS); this.showDraftCovenantHasVirusError = false; this.showDraftCovenantVirusScanFailedError = false; - this.showDraftCovenantUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showDraftCovenantHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showDraftCovenantVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showDraftCovenantUnknownError = - !this.showDraftCovenantHasVirusError && !this.showDraftCovenantVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html index ccd8788161..d01819fae6 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.html @@ -137,7 +137,6 @@

    Proposal

    [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" > @@ -182,7 +181,6 @@

    Notification and Public Hearing Requirements

    [showHasVirusError]="showProofOfAdvertisingHasVirusError" [showVirusScanFailedError]="showProofOfAdvertisingVirusScanFailedError" [showVirusScanFailedError]="showProofOfAdvertisingVirusScanFailedError" - [showUnknownError]="showProofOfAdvertisingUnknownError" >
    @@ -203,7 +201,6 @@

    Notification and Public Hearing Requirements

    [showHasVirusError]="showProofOfSignageHasVirusError" [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" - [showUnknownError]="showProofOfSignageUnknownError" >
    @@ -220,7 +217,6 @@

    Notification and Public Hearing Requirements

    [allowMultiple]="true" [showHasVirusError]="showReportOfPublicHearingHasVirusError" [showVirusScanFailedError]="showReportOfPublicHearingVirusScanFailedError" - [showUnknownError]="showReportOfPublicHearingUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts index 08fec7e13c..c2b799792c 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/excl-proposal/excl-proposal.component.ts @@ -28,16 +28,12 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showProofOfAdvertisingHasVirusError = false; showProofOfAdvertisingVirusScanFailedError = false; - showProofOfAdvertisingUnknownError = false; showProofOfSignageHasVirusError = false; showProofOfSignageVirusScanFailedError = false; - showProofOfSignageUnknownError = false; showReportOfPublicHearingHasVirusError = false; showReportOfPublicHearingVirusScanFailedError = false; - showReportOfPublicHearingUnknownError = false; hectares = new FormControl(null, [Validators.required]); shareProperty = new FormControl(null, [Validators.required]); @@ -110,14 +106,11 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -126,14 +119,11 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_ADVERTISING); this.showProofOfAdvertisingHasVirusError = false; this.showProofOfAdvertisingVirusScanFailedError = false; - this.showProofOfAdvertisingUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProofOfAdvertisingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProofOfAdvertisingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProofOfAdvertisingUnknownError = - !this.showProofOfAdvertisingHasVirusError && !this.showProofOfAdvertisingVirusScanFailedError; } } @@ -142,14 +132,11 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_SIGNAGE); this.showProofOfSignageHasVirusError = false; this.showProofOfSignageVirusScanFailedError = false; - this.showProofOfSignageUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProofOfSignageHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProofOfSignageVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProofOfSignageUnknownError = - !this.showProofOfSignageHasVirusError && !this.showProofOfSignageVirusScanFailedError; } } @@ -158,14 +145,11 @@ export class ExclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING); this.showReportOfPublicHearingHasVirusError = false; this.showReportOfPublicHearingVirusScanFailedError = false; - this.showReportOfPublicHearingUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReportOfPublicHearingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReportOfPublicHearingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReportOfPublicHearingUnknownError = - !this.showReportOfPublicHearingHasVirusError && !this.showReportOfPublicHearingVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html index 4009d427d0..7173b614d6 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.html @@ -127,7 +127,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" >
    @@ -218,7 +217,6 @@

    Notification and Public Hearing Requirements

    [allowMultiple]="true" [showHasVirusError]="showProofOfAdvertisingHasVirusError" [showVirusScanFailedError]="showProofOfAdvertisingVirusScanFailedError" - [showUnknownError]="showProofOfAdvertisingUnknownError" >
    @@ -240,7 +238,6 @@

    Notification and Public Hearing Requirements

    [showHasVirusError]="showProofOfSignageHasVirusError" [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" [showVirusScanFailedError]="showProofOfSignageVirusScanFailedError" - [showUnknownError]="showProofOfSignageUnknownError" >
    @@ -257,7 +254,6 @@

    Notification and Public Hearing Requirements

    [disabled]="disableNotificationFileUploads" [showHasVirusError]="showReportOfPublicHearingHasVirusError" [showVirusScanFailedError]="showReportOfPublicHearingVirusScanFailedError" - [showUnknownError]="showReportOfPublicHearingUnknownError" [allowMultiple]="true" >
    diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts index 3fdd1be94b..240618bd47 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/incl-proposal/incl-proposal.component.ts @@ -40,16 +40,12 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showProofOfAdvertisingHasVirusError = false; showProofOfAdvertisingVirusScanFailedError = false; - showProofOfAdvertisingUnknownError = false; showProofOfSignageHasVirusError = false; showProofOfSignageVirusScanFailedError = false; - showProofOfSignageUnknownError = false; showReportOfPublicHearingHasVirusError = false; showReportOfPublicHearingVirusScanFailedError = false; - showReportOfPublicHearingUnknownError = false; hectares = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); @@ -142,14 +138,11 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -158,14 +151,11 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_ADVERTISING); this.showProofOfAdvertisingHasVirusError = false; this.showProofOfAdvertisingVirusScanFailedError = false; - this.showProofOfAdvertisingUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProofOfAdvertisingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProofOfAdvertisingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProofOfAdvertisingUnknownError = - !this.showProofOfAdvertisingHasVirusError && !this.showProofOfAdvertisingVirusScanFailedError; } } @@ -174,14 +164,11 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROOF_OF_SIGNAGE); this.showProofOfSignageHasVirusError = false; this.showProofOfSignageVirusScanFailedError = false; - this.showProofOfSignageUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProofOfSignageHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProofOfSignageVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProofOfSignageUnknownError = - !this.showProofOfSignageHasVirusError && !this.showProofOfSignageVirusScanFailedError; } } @@ -190,14 +177,11 @@ export class InclProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.REPORT_OF_PUBLIC_HEARING); this.showReportOfPublicHearingHasVirusError = false; this.showReportOfPublicHearingVirusScanFailedError = false; - this.showReportOfPublicHearingUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReportOfPublicHearingHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReportOfPublicHearingVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReportOfPublicHearingUnknownError = - !this.showReportOfPublicHearingHasVirusError && !this.showReportOfPublicHearingVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html index 5b1fd33158..91d0423303 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.html @@ -641,7 +641,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" > @@ -660,7 +659,6 @@

    Proposal

    [showErrors]="showErrors" [showHasVirusError]="showBuildingPlanHasVirusError" [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" - [showUnknownError]="showBuildingPlanUnknownError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts index 4043dcc7a6..b7296fdb4f 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/naru-proposal/naru-proposal.component.ts @@ -36,10 +36,8 @@ export class NaruProposalComponent extends FilesStepComponent implements OnInit, showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showBuildingPlanHasVirusError = false; showBuildingPlanVirusScanFailedError = false; - showBuildingPlanUnknownError = false; willBeOverFiveHundredM2 = new FormControl(null, [Validators.required]); willRetainResidence = new FormControl(null, [Validators.required]); @@ -188,14 +186,11 @@ export class NaruProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -204,14 +199,11 @@ export class NaruProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); this.showBuildingPlanHasVirusError = false; this.showBuildingPlanVirusScanFailedError = false; - this.showBuildingPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showBuildingPlanUnknownError = - !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html index 3c97cf7715..19fc39d22e 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.html @@ -122,7 +122,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts index b629a68b96..13e030b3fa 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/nfu-proposal/nfu-proposal.component.ts @@ -28,7 +28,6 @@ export class NfuProposalComponent extends FilesStepComponent implements OnInit, fillTableDisabled = true; showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; hectares = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); @@ -110,14 +109,11 @@ export class NfuProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html index 46e9c47f1d..0ee431e81c 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.html @@ -703,7 +703,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" >
    @@ -731,7 +730,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showCrossSectionHasVirusError" [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" - [showUnknownError]="showCrossSectionUnknownError" > @@ -761,7 +759,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showReclamationPlanHasVirusError" [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" - [showUnknownError]="showReclamationPlanUnknownError" > @@ -782,7 +779,6 @@

    Proposal

    [showErrors]="showErrors" [showHasVirusError]="showBuildingPlanHasVirusError" [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" - [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="true" [allowMultiple]="true" > @@ -890,7 +886,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showNoticeOfWorkHasVirusError" [showVirusScanFailedError]="showNoticeOfWorkVirusScanFailedError" - [showUnknownError]="showNoticeOfWorkUnknownError" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts index f95426e8e1..a30c6f11c3 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pfrs-proposal/pfrs-proposal.component.ts @@ -57,19 +57,14 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showCrossSectionHasVirusError = false; showCrossSectionVirusScanFailedError = false; - showCrossSectionUnknownError = false; showReclamationPlanHasVirusError = false; showReclamationPlanVirusScanFailedError = false; - showReclamationPlanUnknownError = false; showBuildingPlanHasVirusError = false; showBuildingPlanVirusScanFailedError = false; - showBuildingPlanUnknownError = false; showNoticeOfWorkHasVirusError = false; showNoticeOfWorkVirusScanFailedError = false; - showNoticeOfWorkUnknownError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); @@ -242,14 +237,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -258,14 +250,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); this.showCrossSectionHasVirusError = false; this.showCrossSectionVirusScanFailedError = false; - this.showCrossSectionUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showCrossSectionUnknownError = - !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; } } @@ -274,14 +263,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); this.showReclamationPlanHasVirusError = false; this.showReclamationPlanVirusScanFailedError = false; - this.showReclamationPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReclamationPlanUnknownError = - !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; } } @@ -290,14 +276,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); this.showBuildingPlanHasVirusError = false; this.showBuildingPlanVirusScanFailedError = false; - this.showBuildingPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showBuildingPlanUnknownError = - !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; } } @@ -306,14 +289,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); this.showNoticeOfWorkHasVirusError = false; this.showNoticeOfWorkVirusScanFailedError = false; - this.showNoticeOfWorkUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showNoticeOfWorkHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showNoticeOfWorkVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showNoticeOfWorkUnknownError = - !this.showNoticeOfWorkHasVirusError && !this.showNoticeOfWorkVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html index d11e6ad8ad..694be894c0 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.html @@ -613,7 +613,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" > @@ -641,7 +640,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showCrossSectionHasVirusError" [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" - [showUnknownError]="showCrossSectionUnknownError" > @@ -671,7 +669,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showReclamationPlanHasVirusError" [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" - [showUnknownError]="showReclamationPlanUnknownError" > @@ -692,7 +689,6 @@

    Proposal

    [showErrors]="showErrors" [showHasVirusError]="showBuildingPlanHasVirusError" [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" - [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="true" [allowMultiple]="true" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts index 861e6dcf58..28f920fcac 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/pofo-proposal/pofo-proposal.component.ts @@ -56,16 +56,12 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showCrossSectionHasVirusError = false; showCrossSectionVirusScanFailedError = false; - showCrossSectionUnknownError = false; showReclamationPlanHasVirusError = false; showReclamationPlanVirusScanFailedError = false; - showReclamationPlanUnknownError = false; showBuildingPlanHasVirusError = false; showBuildingPlanVirusScanFailedError = false; - showBuildingPlanUnknownError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); @@ -201,14 +197,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -217,14 +210,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); this.showCrossSectionHasVirusError = false; this.showCrossSectionVirusScanFailedError = false; - this.showCrossSectionUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showCrossSectionUnknownError = - !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; } } @@ -233,14 +223,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); this.showReclamationPlanHasVirusError = false; this.showReclamationPlanVirusScanFailedError = false; - this.showReclamationPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReclamationPlanUnknownError = - !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; } } @@ -249,14 +236,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); this.showBuildingPlanHasVirusError = false; this.showBuildingPlanVirusScanFailedError = false; - this.showBuildingPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showBuildingPlanUnknownError = - !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html index 5340e6357b..097f44ab52 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.html @@ -581,7 +581,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" > @@ -609,7 +608,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showCrossSectionHasVirusError" [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" - [showUnknownError]="showCrossSectionUnknownError" > @@ -639,7 +637,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showReclamationPlanHasVirusError" [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" - [showUnknownError]="showReclamationPlanUnknownError" > @@ -660,7 +657,6 @@

    Proposal

    [showErrors]="showErrors" [showHasVirusError]="showBuildingPlanHasVirusError" [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" - [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="true" [allowMultiple]="true" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts index 2e24426d7e..2f1ee76a8d 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/roso-proposal/roso-proposal.component.ts @@ -56,16 +56,12 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showCrossSectionHasVirusError = false; showCrossSectionVirusScanFailedError = false; - showCrossSectionUnknownError = false; showReclamationPlanHasVirusError = false; showReclamationPlanVirusScanFailedError = false; - showReclamationPlanUnknownError = false; showBuildingPlanHasVirusError = false; showBuildingPlanVirusScanFailedError = false; - showBuildingPlanUnknownError = false; isNewStructure = new FormControl(null, [Validators.required]); isFollowUp = new FormControl(null, [Validators.required]); @@ -198,14 +194,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -214,14 +207,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); this.showCrossSectionHasVirusError = false; this.showCrossSectionVirusScanFailedError = false; - this.showCrossSectionUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showCrossSectionUnknownError = - !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; } } @@ -230,14 +220,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); this.showReclamationPlanHasVirusError = false; this.showReclamationPlanVirusScanFailedError = false; - this.showReclamationPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReclamationPlanUnknownError = - !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; } } @@ -246,14 +233,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); this.showBuildingPlanHasVirusError = false; this.showBuildingPlanVirusScanFailedError = false; - this.showBuildingPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showBuildingPlanUnknownError = - !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html index b21db024e0..db08232046 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.html @@ -217,7 +217,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" >
    @@ -275,7 +274,6 @@

    Proposal

    [disabled]="isHomeSiteSeverance.getRawValue() !== 'true'" [showHasVirusError]="showHomesiteSeveranceHasVirusError" [showVirusScanFailedError]="showHomesiteSeveranceVirusScanFailedError" - [showUnknownError]="showHomesiteSeveranceUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts index 89287b2940..2b9c66617f 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/subd-proposal/subd-proposal.component.ts @@ -34,10 +34,8 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit, showHomesiteSeveranceHasVirusError = false; showProposalMapVirusScanFailedError = false; - showHomesiteSeveranceUnknownError = false; showProposalMapHasVirusError = false; showHomesiteSeveranceVirusScanFailedError = false; - showProposalMapUnknownError = false; lotsProposed = new FormControl(null, [Validators.required]); purpose = new FormControl(null, [Validators.required]); @@ -129,14 +127,11 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -145,14 +140,11 @@ export class SubdProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.HOMESITE_SEVERANCE); this.showHomesiteSeveranceHasVirusError = false; this.showHomesiteSeveranceVirusScanFailedError = false; - this.showHomesiteSeveranceUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showHomesiteSeveranceHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showHomesiteSeveranceVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showHomesiteSeveranceUnknownError = - !this.showHomesiteSeveranceHasVirusError && !this.showHomesiteSeveranceVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html index 3f33cf56c1..f72b17cfab 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.html @@ -180,7 +180,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showServingNoticeHasVirusError" [showVirusScanFailedError]="showServingNoticeVirusScanFailedError" - [showUnknownError]="showServingNoticeUnknownError" data-testid="proof-of-serving-notice-filechooser" > @@ -197,7 +196,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" data-testid="proposal-map-filechooser" > diff --git a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts index e3a132464a..b640d60b21 100644 --- a/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts +++ b/portal-frontend/src/app/features/applications/edit-submission/proposal/tur-proposal/tur-proposal.component.ts @@ -29,10 +29,8 @@ export class TurProposalComponent extends FilesStepComponent implements OnInit, showServingNoticeHasVirusError = false; showServingNoticeVirusScanFailedError = false; - showServingNoticeUnknownError = false; showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; purpose = new FormControl(null, [Validators.required]); outsideLands = new FormControl(null, [Validators.required]); @@ -93,14 +91,11 @@ export class TurProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -109,14 +104,11 @@ export class TurProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.SERVING_NOTICE); this.showServingNoticeHasVirusError = false; this.showServingNoticeVirusScanFailedError = false; - this.showServingNoticeUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showServingNoticeHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showServingNoticeVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showServingNoticeUnknownError = - !this.showServingNoticeHasVirusError && !this.showServingNoticeVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html index 2b9e002235..b2656719a3 100644 --- a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html +++ b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.html @@ -20,7 +20,6 @@

    Attachments

    [showErrors]="showErrors" [showHasVirusError]="showResolutionHasVirusError" [showVirusScanFailedError]="showResolutionVirusScanFailedError" - [showUnknownError]="showResolutionUnknownError" >
    @@ -35,7 +34,6 @@

    Attachments

    [showErrors]="showErrors" [showHasVirusError]="showStaffReportHasVirusError" [showVirusScanFailedError]="showStaffReportVirusScanFailedError" - [showUnknownError]="showStaffReportUnknownError" >
    @@ -49,7 +47,6 @@

    Attachments

    [allowMultiple]="true" [showHasVirusError]="showOtherHasVirusError" [showVirusScanFailedError]="showOtherVirusScanFailedError" - [showUnknownError]="showOtherUnknownError" >
    diff --git a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts index e5f8cc7525..0fae15d00d 100644 --- a/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts +++ b/portal-frontend/src/app/features/applications/review-submission/review-attachments/review-attachments.component.ts @@ -36,13 +36,10 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { showResolutionHasVirusError = false; showResolutionVirusScanFailedError = false; - showResolutionUnknownError = false; showStaffReportHasVirusError = false; showStaffReportVirusScanFailedError = false; - showStaffReportUnknownError = false; showOtherHasVirusError = false; showOtherVirusScanFailedError = false; - showOtherUnknownError = false; constructor( private applicationReviewService: ApplicationSubmissionReviewService, @@ -98,14 +95,11 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { await this.attachFile(fileHandle, DOCUMENT_TYPE.STAFF_REPORT); this.showStaffReportHasVirusError = false; this.showStaffReportVirusScanFailedError = false; - this.showStaffReportUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showStaffReportHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showStaffReportVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showStaffReportUnknownError = - !this.showStaffReportHasVirusError && !this.showStaffReportVirusScanFailedError; } } @@ -114,13 +108,11 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { await this.attachFile(fileHandle, DOCUMENT_TYPE.RESOLUTION_DOCUMENT); this.showResolutionHasVirusError = false; this.showResolutionVirusScanFailedError = false; - this.showResolutionUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showResolutionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showResolutionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showResolutionUnknownError = !this.showResolutionHasVirusError && !this.showResolutionVirusScanFailedError; } } @@ -129,13 +121,11 @@ export class ReviewAttachmentsComponent implements OnInit, OnDestroy { await this.attachFile(fileHandle, DOCUMENT_TYPE.OTHER); this.showOtherHasVirusError = false; this.showOtherVirusScanFailedError = false; - this.showOtherUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showOtherHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showOtherVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showOtherUnknownError = !this.showOtherHasVirusError && this.showOtherVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html index 1ed087fd69..8861eeceff 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.html @@ -404,7 +404,6 @@

    Additional Proposal Information

    [showErrors]="showErrors" [showHasVirusError]="showBuildingPlanHasVirusError" [showVirusScanFailedError]="showBuildingPlanVirusScanFailedError" - [showUnknownError]="showBuildingPlanUnknownError" [isRequired]="confirmRemovalOfSoil" [allowMultiple]="true" [disabled]="!confirmRemovalOfSoil" diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts index 5f33175b6d..8f068dd154 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/additional-information/additional-information.component.ts @@ -98,7 +98,6 @@ export class AdditionalInformationComponent extends FilesStepComponent implement confirmRemovalOfSoil = false; showBuildingPlanHasVirusError = false; showBuildingPlanVirusScanFailedError = false; - showBuildingPlanUnknownError = false; buildingPlans: NoticeOfIntentDocumentDto[] = []; proposedStructures: FormProposedStructure[] = []; @@ -202,14 +201,11 @@ export class AdditionalInformationComponent extends FilesStepComponent implement await this.attachFile(file, DOCUMENT_TYPE.BUILDING_PLAN); this.showBuildingPlanHasVirusError = false; this.showBuildingPlanVirusScanFailedError = false; - this.showBuildingPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showBuildingPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showBuildingPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showBuildingPlanUnknownError = - !this.showBuildingPlanHasVirusError && !this.showBuildingPlanVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 1f1c471575..a915d3aa02 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -12,7 +12,6 @@

    {{ title }} optional attachment

    [isRequired]="true" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index 686eb7d075..bf241c192a 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -26,7 +26,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { isSaving = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; showFileRequiredError = false; title: string = ''; isEditing = false; @@ -150,7 +149,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; const documents = await this.noticeOfIntentDocumentService.getByFileId(this.data.fileId); if (documents) { @@ -183,7 +181,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { this.isFileDirty = true; this.isSaving = false; } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async onEdit() { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts index 10f151a525..1ff2735298 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/other-attachments/other-attachments.component.ts @@ -36,7 +36,6 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI private documentCodes: DocumentTypeDto[] = []; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; isMobile = window.innerWidth <= MOBILE_BREAKPOINT; constructor( @@ -76,13 +75,11 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI await this.attachFile(file, null); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html index 37506f60c8..216735720f 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.html @@ -240,7 +240,6 @@ [isRequired]="isCertificateOfTitleRequired" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" [disabled]="parcelForm.controls.pid.disabled" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts index 9d348a44ea..37416f4df0 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/parcels/parcel-entry/parcel-entry.component.ts @@ -69,7 +69,6 @@ export class ParcelEntryComponent implements OnInit { isCertificateOfTitleRequired = true; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; isMobile = false; parcelType = new FormControl(null, [Validators.required]); @@ -317,7 +316,6 @@ export class ParcelEntryComponent implements OnInit { this.toastService.showSuccessToast('Document uploaded'); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; return; } catch (err) { this.toastService.showErrorToast('Document upload failed'); @@ -328,7 +326,6 @@ export class ParcelEntryComponent implements OnInit { } } } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async deleteFile($event: NoticeOfIntentDocumentDto) { diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html index 58959a7fa8..a84922a9e7 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.html @@ -220,7 +220,6 @@

    [isRequired]="needsAuthorizationLetter" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts index 7dc914879b..989b908965 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/primary-contact/primary-contact.component.ts @@ -40,7 +40,6 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni needsAuthorizationLetter = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; selectedThirdPartyAgent: boolean | null = false; selectedLocalGovernment = false; _selectedOwnerUuid: string | undefined = undefined; @@ -111,14 +110,11 @@ export class PrimaryContactComponent extends FilesStepComponent implements OnIni await this.attachFile(file, DOCUMENT_TYPE.AUTHORIZATION_LETTER); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showUnknownError = - !this.showHasVirusError && !this.showVirusScanFailedError && !this.showVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html index 2607514ee6..608c39f794 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.html @@ -279,7 +279,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" > @@ -376,7 +375,6 @@

    Proposal

    [disabled]="!allowMiningUploads" [showHasVirusError]="showCrossSectionHasVirusError" [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" - [showUnknownError]="showCrossSectionUnknownError" >
    @@ -406,7 +404,6 @@

    Proposal

    [disabled]="!allowMiningUploads" [showHasVirusError]="showReclamationPlanHasVirusError" [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" - [showUnknownError]="showReclamationPlanUnknownError" >
    @@ -472,7 +469,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showNoticeOfWorkHasVirusError" [showVirusScanFailedError]="showNoticeOfWorkVirusScanFailedError" - [showUnknownError]="showNoticeOfWorkUnknownError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts index 2651531e7b..dc811f568d 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pfrs/pfrs-proposal.component.ts @@ -37,16 +37,12 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, requiresNoticeOfWork = false; showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showCrossSectionHasVirusError = false; showCrossSectionVirusScanFailedError = false; - showCrossSectionUnknownError = false; showReclamationPlanHasVirusError = false; showReclamationPlanVirusScanFailedError = false; - showReclamationPlanUnknownError = false; showNoticeOfWorkHasVirusError = false; showNoticeOfWorkVirusScanFailedError = false; - showNoticeOfWorkUnknownError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; @@ -179,14 +175,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -195,14 +188,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); this.showCrossSectionHasVirusError = false; this.showCrossSectionVirusScanFailedError = false; - this.showCrossSectionUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showCrossSectionUnknownError = - !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; } } @@ -211,14 +201,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); this.showReclamationPlanHasVirusError = false; this.showReclamationPlanVirusScanFailedError = false; - this.showReclamationPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReclamationPlanUnknownError = - !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; } } @@ -227,14 +214,11 @@ export class PfrsProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); this.showNoticeOfWorkHasVirusError = false; this.showNoticeOfWorkVirusScanFailedError = false; - this.showNoticeOfWorkUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showNoticeOfWorkHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showNoticeOfWorkVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showNoticeOfWorkUnknownError = - !this.showNoticeOfWorkHasVirusError && !this.showNoticeOfWorkVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html index ea08764d3a..bd4462b0ce 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.html @@ -197,7 +197,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" > @@ -254,7 +253,6 @@

    Proposal

    [disabled]="!allowMiningUploads" [showHasVirusError]="showCrossSectionHasVirusError" [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" - [showUnknownError]="showCrossSectionUnknownError" >
    @@ -284,7 +282,6 @@

    Proposal

    [disabled]="!allowMiningUploads" [showHasVirusError]="showReclamationPlanHasVirusError" [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" - [showUnknownError]="showReclamationPlanUnknownError" >
    diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts index c6394ce3db..731d365a74 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/pofo/pofo-proposal.component.ts @@ -30,13 +30,10 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, allowMiningUploads = false; showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showCrossSectionHasVirusError = false; showCrossSectionVirusScanFailedError = false; - showCrossSectionUnknownError = false; showReclamationPlanHasVirusError = false; showReclamationPlanVirusScanFailedError = false; - showReclamationPlanUnknownError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; @@ -128,13 +125,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = !this.showProposalMapHasVirusError; } } @@ -143,14 +138,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); this.showCrossSectionHasVirusError = false; this.showCrossSectionVirusScanFailedError = false; - this.showCrossSectionUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showCrossSectionUnknownError = - !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; } } @@ -159,13 +151,11 @@ export class PofoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); this.showReclamationPlanHasVirusError = false; this.showReclamationPlanVirusScanFailedError = false; - this.showReclamationPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReclamationPlanUnknownError = !this.showReclamationPlanHasVirusError; } } diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html index abf78b8d13..777fdfd5fe 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.html @@ -182,7 +182,6 @@

    Proposal

    [isRequired]="true" [showHasVirusError]="showProposalMapHasVirusError" [showVirusScanFailedError]="showProposalMapVirusScanFailedError" - [showUnknownError]="showProposalMapUnknownError" > @@ -243,7 +242,6 @@

    Proposal

    [disabled]="!allowMiningUploads" [showHasVirusError]="showCrossSectionHasVirusError" [showVirusScanFailedError]="showCrossSectionVirusScanFailedError" - [showUnknownError]="showCrossSectionUnknownError" >
    @@ -273,7 +271,6 @@

    Proposal

    [disabled]="!allowMiningUploads" [showHasVirusError]="showReclamationPlanHasVirusError" [showVirusScanFailedError]="showReclamationPlanVirusScanFailedError" - [showUnknownError]="showReclamationPlanUnknownError" >
    @@ -332,7 +329,6 @@

    Proposal

    [allowMultiple]="true" [showHasVirusError]="showNoticeOfWorkHasVirusError" [showVirusScanFailedError]="showNoticeOfWorkVirusScanFailedError" - [showUnknownError]="showNoticeOfWorkUnknownError" > diff --git a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts index 2c90215386..023f382523 100644 --- a/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts +++ b/portal-frontend/src/app/features/notice-of-intents/edit-submission/proposal/roso/roso-proposal.component.ts @@ -31,16 +31,12 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, requiresNoticeOfWork = false; showProposalMapHasVirusError = false; showProposalMapVirusScanFailedError = false; - showProposalMapUnknownError = false; showCrossSectionHasVirusError = false; showCrossSectionVirusScanFailedError = false; - showCrossSectionUnknownError = false; showReclamationPlanHasVirusError = false; showReclamationPlanVirusScanFailedError = false; - showReclamationPlanUnknownError = false; showNoticeOfWorkHasVirusError = false; showNoticeOfWorkVirusScanFailedError = false; - showNoticeOfWorkUnknownError = false; proposalMap: NoticeOfIntentDocumentDto[] = []; crossSections: NoticeOfIntentDocumentDto[] = []; @@ -145,14 +141,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.PROPOSAL_MAP); this.showProposalMapHasVirusError = false; this.showProposalMapVirusScanFailedError = false; - this.showProposalMapUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showProposalMapHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showProposalMapVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showProposalMapUnknownError = - !this.showProposalMapHasVirusError && !this.showProposalMapVirusScanFailedError; } } @@ -161,14 +154,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.CROSS_SECTIONS); this.showCrossSectionHasVirusError = false; this.showCrossSectionVirusScanFailedError = false; - this.showCrossSectionUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showCrossSectionHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showCrossSectionVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showCrossSectionUnknownError = - !this.showCrossSectionHasVirusError && !this.showCrossSectionVirusScanFailedError; } } @@ -177,14 +167,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.RECLAMATION_PLAN); this.showReclamationPlanHasVirusError = false; this.showReclamationPlanVirusScanFailedError = false; - this.showReclamationPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showReclamationPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showReclamationPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showReclamationPlanUnknownError = - !this.showReclamationPlanHasVirusError && !this.showReclamationPlanVirusScanFailedError; } } @@ -193,14 +180,11 @@ export class RosoProposalComponent extends FilesStepComponent implements OnInit, await this.attachFile(file, DOCUMENT_TYPE.NOTICE_OF_WORK); this.showNoticeOfWorkHasVirusError = false; this.showNoticeOfWorkVirusScanFailedError = false; - this.showNoticeOfWorkUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showNoticeOfWorkHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showNoticeOfWorkVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showNoticeOfWorkUnknownError = - !this.showNoticeOfWorkHasVirusError && !this.showNoticeOfWorkVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html index 94a807d5f4..c83eb82cf4 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.html @@ -12,7 +12,6 @@

    {{ title }} optional attachment

    [isRequired]="true" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts index b261fb6c5d..4031f5008e 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments-upload-dialog/other-attachments-upload-dialog.component.ts @@ -26,7 +26,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { isSaving = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; showFileRequiredError = false; title: string = ''; isEditing = false; @@ -152,7 +151,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { await this.data.otherAttachmentsComponent.attachFile(this.pendingFile!, null); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; const documents = await this.notificationDocumentService.getByFileId(this.data.fileId); if (documents) { @@ -185,7 +183,6 @@ export class OtherAttachmentsUploadDialogComponent implements OnInit { this.isFileDirty = true; this.isSaving = false; } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } async onEdit() { diff --git a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts index 3d9eae8092..bef9e6d4cc 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/other-attachments/other-attachments.component.ts @@ -36,7 +36,6 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI private isDirty = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; isMobile = window.innerWidth <= MOBILE_BREAKPOINT; private documentCodes: DocumentTypeDto[] = []; @@ -78,13 +77,11 @@ export class OtherAttachmentsComponent extends FilesStepComponent implements OnI await this.attachFile(file, null); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; } } diff --git a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html index 93eaf9707e..9c9d155aa0 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html +++ b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.html @@ -79,7 +79,6 @@

    Purpose of SRW

    [isRequired]="true" [showHasVirusError]="showSRWTermsHasVirusError" [showVirusScanFailedError]="showSRWTermsVirusScanFailedError" - [showUnknownError]="showSRWTermsHasVirusError" > @@ -126,7 +125,6 @@

    Purpose of SRW

    [allowMultiple]="true" [showHasVirusError]="showSurveyPlanHasVirusError" [showVirusScanFailedError]="showSurveyPlanVirusScanFailedError" - [showUnknownError]="showSurveyPlanUnknownError" > diff --git a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts index c54107a12a..74f3cc5639 100644 --- a/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts +++ b/portal-frontend/src/app/features/notifications/edit-submission/proposal/proposal.component.ts @@ -51,10 +51,8 @@ export class ProposalComponent extends FilesStepComponent implements OnInit, OnD surveyForm = new FormGroup({} as any); showSRWTermsHasVirusError = false; showSRWTermsVirusScanFailedError = false; - showSRWTermsUnknownError = false; showSurveyPlanHasVirusError = false; showSurveyPlanVirusScanFailedError = false; - showSurveyPlanUnknownError = false; constructor( private router: Router, @@ -107,13 +105,11 @@ export class ProposalComponent extends FilesStepComponent implements OnInit, OnD await this.attachFile(file, DOCUMENT_TYPE.SRW_TERMS); this.showSRWTermsHasVirusError = false; this.showSRWTermsVirusScanFailedError = false; - this.showSRWTermsUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showSRWTermsHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showSRWTermsVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showSRWTermsUnknownError = !this.showSRWTermsHasVirusError && !this.showSRWTermsVirusScanFailedError; } } @@ -122,13 +118,11 @@ export class ProposalComponent extends FilesStepComponent implements OnInit, OnD await this.attachFile(file, DOCUMENT_TYPE.SURVEY_PLAN); this.showSurveyPlanHasVirusError = false; this.showSurveyPlanVirusScanFailedError = false; - this.showSurveyPlanUnknownError = false; } catch (err) { if (err instanceof HttpErrorResponse) { this.showSurveyPlanHasVirusError = err.status === 400 && err.error.name === 'VirusDetected'; this.showSurveyPlanVirusScanFailedError = err.status === 500 && err.error.name === 'VirusScanFailed'; } - this.showSurveyPlanUnknownError = !this.showSurveyPlanHasVirusError && !this.showSurveyPlanVirusScanFailedError; } } diff --git a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html index 175c4a3578..13dd3e1010 100644 --- a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html +++ b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.html @@ -29,10 +29,7 @@ 'desktop-file-drag-drop': true, 'error-outline': !disabled && - ((isRequired && showErrors && !uploadedFiles.length) || - showHasVirusError || - showVirusScanFailedError || - showUnknownError), + ((isRequired && showErrors && !uploadedFiles.length) || showHasVirusError || showVirusScanFailedError), disabled: disabled, }" dragDropFile @@ -66,7 +63,4 @@ A problem occurred while scanning for viruses. Please try again. - - There was a problem uploading the file. Please try again. - Maximum file size: 100 MB diff --git a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts index f695674846..2dae680114 100644 --- a/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts +++ b/portal-frontend/src/app/shared/file-drag-drop/file-drag-drop.component.ts @@ -21,7 +21,6 @@ export class FileDragDropComponent implements OnInit { @Input() showErrors = false; @Input() showHasVirusError = false; @Input() showVirusScanFailedError = false; - @Input() showUnknownError = false; private uploadClicked = false; diff --git a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html index bf96df55fc..22671f2f9e 100644 --- a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html +++ b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.html @@ -48,7 +48,6 @@
    [isRequired]="true" [showHasVirusError]="showHasVirusError" [showVirusScanFailedError]="showVirusScanFailedError" - [showUnknownError]="showUnknownError" > diff --git a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts index c9ee9d3a12..237573d808 100644 --- a/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts +++ b/portal-frontend/src/app/shared/owner-dialogs/owner-dialog/owner-dialog.component.ts @@ -42,7 +42,6 @@ export class OwnerDialogComponent { isEdit = false; showHasVirusError = false; showVirusScanFailedError = false; - showUnknownError = false; existingUuid: string | undefined; files: ApplicationDocumentDto[] = []; showFileErrors = false; @@ -278,7 +277,6 @@ export class OwnerDialogComponent { this.toastService.showSuccessToast('Document uploaded'); this.showHasVirusError = false; this.showVirusScanFailedError = false; - this.showUnknownError = false; return documentUuid; } catch (err) { if (err instanceof HttpErrorResponse) { @@ -291,7 +289,6 @@ export class OwnerDialogComponent { this.toastService.showErrorToast('Document upload failed'); } } - this.showUnknownError = !this.showHasVirusError && !this.showVirusScanFailedError; return; } From a7af049735acd4e2f536df042403e8b9cdc368a4 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 12:08:35 -0800 Subject: [PATCH 29/30] Remove smiley --- services/apps/alcs/src/document/document.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/apps/alcs/src/document/document.service.ts b/services/apps/alcs/src/document/document.service.ts index bf0fe1b866..70d3bfb741 100644 --- a/services/apps/alcs/src/document/document.service.ts +++ b/services/apps/alcs/src/document/document.service.ts @@ -176,7 +176,7 @@ export class DocumentService { if (isInfected) { await this.deleteDocument(data.fileKey); this.logger.warn(`Deleted malicious file ${data.fileKey}`); - throw new ServiceValidationException('File may contain malicious data, upload blocked :P', 'VirusDetected'); + throw new ServiceValidationException('File may contain malicious data, upload blocked', 'VirusDetected'); } return this.documentRepository.save( From cebe693dd54938d9c06ea71cfda169f1fd6a67e4 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:59:40 -0800 Subject: [PATCH 30/30] Make tests pass --- .../documents/documents.component.spec.ts | 12 + .../documents/documents.component.spec.ts | 12 + .../document-upload-dialog.component.spec.ts | 205 +++++------------- .../application-parcel.service.spec.ts | 23 +- .../notice-of-intent-parcel.service.spec.ts | 22 +- .../apps/alcs/src/clamav/clamav.service.ts | 1 + .../src/exceptions/exception.filter.spec.ts | 6 +- 7 files changed, 89 insertions(+), 192 deletions(-) diff --git a/alcs-frontend/src/app/features/application/documents/documents.component.spec.ts b/alcs-frontend/src/app/features/application/documents/documents.component.spec.ts index 4ddbc4a6c3..adba41a180 100644 --- a/alcs-frontend/src/app/features/application/documents/documents.component.spec.ts +++ b/alcs-frontend/src/app/features/application/documents/documents.component.spec.ts @@ -10,6 +10,8 @@ import { ApplicationDto } from '../../../services/application/application.dto'; import { ToastService } from '../../../services/toast/toast.service'; import { DocumentsComponent } from './documents.component'; +import { ApplicationParcelService } from '../../../services/application/application-parcel/application-parcel.service'; +import { ApplicationSubmissionService } from '../../../services/application/application-submission/application-submission.service'; describe('DocumentsComponent', () => { let component: DocumentsComponent; @@ -19,6 +21,8 @@ describe('DocumentsComponent', () => { let mockDialog: DeepMocked; let mockToastService: DeepMocked; let mockAppSubStatusService: DeepMocked; + let mockAppSubService: DeepMocked; + let mockAppParcelService: DeepMocked; beforeEach(async () => { mockAppDocService = createMock(); @@ -50,6 +54,14 @@ describe('DocumentsComponent', () => { provide: ApplicationSubmissionStatusService, useValue: mockAppSubStatusService, }, + { + provide: ApplicationSubmissionService, + useValue: mockAppSubService, + }, + { + provide: ApplicationParcelService, + useValue: mockAppParcelService, + }, ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); diff --git a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.spec.ts b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.spec.ts index 35bc315067..d058c65757 100644 --- a/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.spec.ts +++ b/alcs-frontend/src/app/features/notice-of-intent/documents/documents.component.spec.ts @@ -10,6 +10,8 @@ import { NoticeOfIntentDto } from '../../../services/notice-of-intent/notice-of- import { ToastService } from '../../../services/toast/toast.service'; import { NoiDocumentsComponent } from './documents.component'; +import { NoticeOfIntentSubmissionService } from '../../../services/notice-of-intent/notice-of-intent-submission/notice-of-intent-submission.service'; +import { NoticeOfIntentParcelService } from '../../../services/notice-of-intent/notice-of-intent-parcel/notice-of-intent-parcel.service'; describe('NoiDocumentsComponent', () => { let component: NoiDocumentsComponent; @@ -19,6 +21,8 @@ describe('NoiDocumentsComponent', () => { let mockDialog: DeepMocked; let mockToastService: DeepMocked; let mockNoiSubStatusService: DeepMocked; + let mockAppSubService: DeepMocked; + let mockAppParcelService: DeepMocked; beforeEach(async () => { mockNoiDocService = createMock(); @@ -51,6 +55,14 @@ describe('NoiDocumentsComponent', () => { provide: NoticeOfIntentSubmissionStatusService, useValue: mockNoiSubStatusService, }, + { + provide: NoticeOfIntentSubmissionService, + useValue: mockAppSubService, + }, + { + provide: NoticeOfIntentParcelService, + useValue: mockAppParcelService, + }, ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); diff --git a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.spec.ts b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.spec.ts index 6e3f34e227..e750d2ccf2 100644 --- a/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.spec.ts +++ b/alcs-frontend/src/app/shared/document-upload-dialog/document-upload-dialog.component.spec.ts @@ -1,150 +1,63 @@ -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, Inject, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { ApplicationDecisionDocumentDto } from '../../services/application/decision/application-decision-v2/application-decision-v2.dto'; -import { ApplicationDecisionV2Service } from '../../services/application/decision/application-decision-v2/application-decision-v2.service'; +import { EventEmitter, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { ApplicationDocumentService } from '../../services/application/application-document/application-document.service'; +import { ApplicationParcelService } from '../../services/application/application-parcel/application-parcel.service'; +import { ApplicationSubmissionService } from '../../services/application/application-submission/application-submission.service'; import { ToastService } from '../../services/toast/toast.service'; -import { DOCUMENT_SOURCE } from '../document/document.dto'; -import { FileHandle } from '../drag-drop-file/drag-drop-file.directive'; -import { splitExtension } from '../utils/file'; -@Component({ - selector: 'app-app-decision-document-upload-dialog', - templateUrl: './decision-document-upload-dialog.component.html', - styleUrls: ['./decision-document-upload-dialog.component.scss'], -}) -export class DecisionDocumentUploadDialogComponent implements OnInit { - title = 'Create'; - isDirty = false; - isSaving = false; - allowsFileEdit = true; - documentType = 'Decision Package'; - - @Output() uploadFiles: EventEmitter = new EventEmitter(); - - name = new FormControl('', [Validators.required]); - type = new FormControl({ disabled: true, value: undefined }, [Validators.required]); - source = new FormControl({ disabled: true, value: DOCUMENT_SOURCE.ALC }, [Validators.required]); - - visibleToInternal = new FormControl({ disabled: true, value: true }, [Validators.required]); - visibleToPublic = new FormControl({ disabled: true, value: true }, [Validators.required]); - - documentSources = Object.values(DOCUMENT_SOURCE); - - form = new FormGroup({ - name: this.name, - type: this.type, - source: this.source, - visibleToInternal: this.visibleToInternal, - visibleToPublic: this.visibleToPublic, +import { DocumentUploadDialogComponent } from './document-upload-dialog.component'; + +describe('DocumentUploadDialogComponent', () => { + let component: DocumentUploadDialogComponent; + let fixture: ComponentFixture; + + let mockAppDocService: DeepMocked; + let mockParcelService: DeepMocked; + let mockSubmissionService: DeepMocked; + + beforeEach(async () => { + mockAppDocService = createMock(); + mockParcelService = createMock(); + mockSubmissionService = createMock(); + + const mockDialogRef = { + close: jest.fn(), + afterClosed: jest.fn(), + subscribe: jest.fn(), + backdropClick: () => new EventEmitter(), + }; + + await TestBed.configureTestingModule({ + declarations: [DocumentUploadDialogComponent], + providers: [ + { + provide: ApplicationDocumentService, + useValue: mockAppDocService, + }, + { + provide: ApplicationParcelService, + useValue: mockParcelService, + }, + { + provide: ApplicationSubmissionService, + useValue: mockSubmissionService, + }, + { provide: MatDialogRef, useValue: mockDialogRef }, + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: ToastService, useValue: {} }, + ], + imports: [MatDialogModule], + schemas: [NO_ERRORS_SCHEMA], + }).compileComponents(); + + fixture = TestBed.createComponent(DocumentUploadDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); }); - pendingFile: File | undefined; - existingFile: string | undefined; - showVirusError = false; - extension = ''; - - constructor( - @Inject(MAT_DIALOG_DATA) - public data: { fileId: string; decisionUuid: string; existingDocument?: ApplicationDecisionDocumentDto }, - protected dialog: MatDialogRef, - private decisionService: ApplicationDecisionV2Service, - private toastService: ToastService, - ) {} - - ngOnInit(): void { - if (this.data.existingDocument) { - const document = this.data.existingDocument; - this.title = 'Edit'; - - const { fileName, extension } = splitExtension(document.fileName); - this.extension = extension; - this.form.patchValue({ - name: fileName, - }); - this.existingFile = document.fileName; - } - } - - async onSubmit() { - const file = this.pendingFile; - if (file) { - const renamedFile = new File([file], this.name.value! + this.extension, { type: file.type }); - this.isSaving = true; - if (this.data.existingDocument) { - await this.decisionService.deleteFile(this.data.decisionUuid, this.data.existingDocument.uuid); - } - - try { - await this.decisionService.uploadFile(this.data.decisionUuid, renamedFile); - } catch (err) { - this.toastService.showErrorToast('Document upload failed'); - if (err instanceof HttpErrorResponse && err.status === 403) { - this.showVirusError = true; - this.isSaving = false; - this.pendingFile = undefined; - return; - } - } - - this.dialog.close(true); - this.isSaving = false; - } else if (this.data.existingDocument) { - this.isSaving = true; - await this.decisionService.updateFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.name.value! + this.extension, - ); - - this.dialog.close(true); - this.isSaving = false; - } - } - - uploadFile(event: Event) { - const element = event.target as HTMLInputElement; - const selectedFiles = element.files; - if (selectedFiles && selectedFiles[0]) { - this.pendingFile = selectedFiles[0]; - const { fileName, extension } = splitExtension(selectedFiles[0].name); - this.name.setValue(fileName); - this.extension = extension; - this.showVirusError = false; - } - } - - onRemoveFile() { - this.pendingFile = undefined; - this.existingFile = undefined; - this.extension = ''; - this.name.setValue(''); - } - - openFile() { - if (this.pendingFile) { - const fileURL = URL.createObjectURL(this.pendingFile); - window.open(fileURL, '_blank'); - } - } - - async openExistingFile() { - if (this.data.existingDocument) { - await this.decisionService.downloadFile( - this.data.decisionUuid, - this.data.existingDocument.uuid, - this.data.existingDocument.fileName, - ); - } - } - - filesDropped($event: FileHandle) { - this.pendingFile = $event.file; - const { fileName, extension } = splitExtension(this.pendingFile.name); - this.extension = extension; - this.name.setValue(fileName); - this.showVirusError = false; - this.uploadFiles.emit($event); - } -} + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/portal-frontend/src/app/services/application-parcel/application-parcel.service.spec.ts b/portal-frontend/src/app/services/application-parcel/application-parcel.service.spec.ts index e9c2afcd58..c96eef6a09 100644 --- a/portal-frontend/src/app/services/application-parcel/application-parcel.service.spec.ts +++ b/portal-frontend/src/app/services/application-parcel/application-parcel.service.spec.ts @@ -1,4 +1,4 @@ -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { createMock, DeepMocked } from '@golevelup/ts-jest'; @@ -99,31 +99,12 @@ describe('ApplicationParcelService', () => { expect(mockHttpClient.put.mock.calls[0][0]).toContain('application-parcel'); }); - it('should show an error toast if updating a parcel fails', async () => { - mockHttpClient.put.mockReturnValue(throwError(() => ({}))); - - await service.update([{}] as ApplicationParcelUpdateDto[]); - - expect(mockHttpClient.put).toHaveBeenCalledTimes(1); - expect(mockToastService.showErrorToast).toHaveBeenCalledTimes(1); - }); - it('should call document service for attaching certificate of title', async () => { mockDocumentService.uploadFile.mockResolvedValue({}); await service.attachCertificateOfTitle('fileId', 'parcelUuid', {} as File); expect(mockDocumentService.uploadFile).toHaveBeenCalledTimes(1); - expect(mockToastService.showSuccessToast).toHaveBeenCalledTimes(1); - }); - - it('should show an error toast if document service fails', async () => { - mockDocumentService.uploadFile.mockRejectedValue({}); - - await service.attachCertificateOfTitle('fileId', 'parcelUuid', {} as File); - - expect(mockDocumentService.uploadFile).toHaveBeenCalledTimes(1); - expect(mockToastService.showErrorToast).toHaveBeenCalledTimes(1); }); it('should make a delete request and show the overlay for removing all parcels', async () => { @@ -147,7 +128,7 @@ describe('ApplicationParcelService', () => { mockHttpClient.delete.mockReturnValue( throwError(() => { new Error(''); - }) + }), ); await service.deleteMany([]); diff --git a/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.spec.ts b/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.spec.ts index e5dc086569..7d223c3f05 100644 --- a/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.spec.ts +++ b/portal-frontend/src/app/services/notice-of-intent-parcel/notice-of-intent-parcel.service.spec.ts @@ -95,35 +95,15 @@ describe('NoticeOfIntentParcelService', () => { await service.update([{ uuid: mockUuid }] as NoticeOfIntentParcelUpdateDto[]); expect(mockHttpClient.put).toHaveBeenCalledTimes(1); - expect(mockToastService.showSuccessToast).toHaveBeenCalledTimes(1); expect(mockHttpClient.put.mock.calls[0][0]).toContain('notice-of-intent-parcel'); }); - it('should show an error toast if updating a parcel fails', async () => { - mockHttpClient.put.mockReturnValue(throwError(() => ({}))); - - await service.update([{}] as NoticeOfIntentParcelUpdateDto[]); - - expect(mockHttpClient.put).toHaveBeenCalledTimes(1); - expect(mockToastService.showErrorToast).toHaveBeenCalledTimes(1); - }); - it('should call document service for attaching certificate of title', async () => { mockDocumentService.uploadFile.mockResolvedValue({}); await service.attachCertificateOfTitle('fileId', 'parcelUuid', {} as File); expect(mockDocumentService.uploadFile).toHaveBeenCalledTimes(1); - expect(mockToastService.showSuccessToast).toHaveBeenCalledTimes(1); - }); - - it('should show an error toast if document service fails', async () => { - mockDocumentService.uploadFile.mockRejectedValue({}); - - await service.attachCertificateOfTitle('fileId', 'parcelUuid', {} as File); - - expect(mockDocumentService.uploadFile).toHaveBeenCalledTimes(1); - expect(mockToastService.showErrorToast).toHaveBeenCalledTimes(1); }); it('should make a delete request and show the overlay for removing all parcels', async () => { @@ -147,7 +127,7 @@ describe('NoticeOfIntentParcelService', () => { mockHttpClient.delete.mockReturnValue( throwError(() => { new Error(''); - }) + }), ); await service.deleteMany([]); diff --git a/services/apps/alcs/src/clamav/clamav.service.ts b/services/apps/alcs/src/clamav/clamav.service.ts index 8d8ba4e348..e8210c66e2 100644 --- a/services/apps/alcs/src/clamav/clamav.service.ts +++ b/services/apps/alcs/src/clamav/clamav.service.ts @@ -1,4 +1,5 @@ import { CONFIG_TOKEN, IConfig } from '@app/common/config/config.module'; +import { BaseServiceException } from '@app/common/exceptions/base.exception'; import { HttpService } from '@nestjs/axios'; import { Inject, Injectable, Logger } from '@nestjs/common'; import * as NodeClam from 'clamscan'; diff --git a/services/libs/common/src/exceptions/exception.filter.spec.ts b/services/libs/common/src/exceptions/exception.filter.spec.ts index 5642d588e5..8ce23bb451 100644 --- a/services/libs/common/src/exceptions/exception.filter.spec.ts +++ b/services/libs/common/src/exceptions/exception.filter.spec.ts @@ -35,10 +35,7 @@ describe('HttpExceptionFilter', () => { }); it('should call global HttpExceptionFilter', () => { - const mockHttpException = new HttpException( - { message: 'Sample Exception' }, - HttpStatus.BAD_REQUEST, - ); + const mockHttpException = new HttpException({ message: 'Sample Exception' }, HttpStatus.BAD_REQUEST); service.catch(mockHttpException, mockArgumentsHost); expect(mockHttpArgumentsHost).toBeCalledTimes(1); @@ -51,6 +48,7 @@ describe('HttpExceptionFilter', () => { expect(mockSend).toBeCalledWith( new BaseErrorResponseModel( mockHttpException.getStatus(), + mockHttpException.name, mockHttpException.message, mockGetRequest().url, ),

    #{{ i + 1 }} + {{ i + 1 }} + Type + Additional Proposal Information Total Floor Area + Additional Proposal Information Action + @@ -165,12 +183,15 @@

    Additional Proposal Information

    - The proposed residential structure and its total floor area must be allowed under the ALC Act and/or ALR Use Regulation. - If not, you may require a 'Non-Adhering Residential Use' application instead. For more info, please see - Housing in the ALR + The proposed residential structure and its total floor area must be allowed under the ALC Act and/or + ALR Use Regulation. If not, you may require a 'Non-Adhering Residential Use' application instead. For + more info, please see + Housing in the ALR on the ALC website.
    -
    +