import { Injectable } from '@angular/core'; import { ApplicationFileService } from '@core/services/application-file.service'; import { PortalDeterminationService } from '@core/services/portal-determination.service'; import { environment } from '@environment'; import { AddressFormatterService, ArrayHelpersService, FileService, PaginationOptions, SimpleStringMap, TypeaheadSelectOption } from '@yourcause/common'; import { I18nService } from '@yourcause/common/i18n'; import { LogService } from '@yourcause/common/logging'; import { NotifierService } from '@yourcause/common/notifier'; import { AttachYCState, BaseYCService } from '@yourcause/common/state'; import { AddressRequestsResources } from './address-requests.resources'; import { AddressRequestsState } from './address-requests.state'; import { AddressRequestApproveApi, AddressRequestFile, AddressRequestFileForUI, AddressRequestForUI, AddressRequestRejectApi, AddressRequestStatus, FileType } from './address-requests.typing'; @AttachYCState(AddressRequestsState) @Injectable({ providedIn: 'root' }) export class AddressRequestsService extends BaseYCService { getAddressRequestsStatusMap ( simple = true ): SimpleStringMap { return { [AddressRequestStatus.Approved]: this.i18n.translate( simple ? 'GLOBAL:textApproved' : 'GLOBAL:textAlternateAddressRequestApproved', {}, simple ? 'Approved' : 'Alternate address request approved' ), [AddressRequestStatus.Rejected]: this.i18n.translate( simple ? 'GLOBAL:textRejected' : 'GLOBAL:textAlternateAddressRequestRejected', {}, simple ? 'Rejected' : 'Alternate address request rejected' ), [AddressRequestStatus.Pending]: this.i18n.translate( simple ? 'common:lblPending' : 'GLOBAL:textAlternateAddressRequestSentToReview', {}, simple ? 'Pending' : 'Alternate address request sent to review' ), [AddressRequestStatus.OnHold]: this.i18n.translate( simple ? 'GLOBAL:textOnHold' : 'GLOBAL:textAlternateAddressRequestSentToReview', {}, simple ? 'On hold' : 'Alternate address request sent to review' ) }; } getAddressRequestStatusOptions (): TypeaheadSelectOption[] { const map = this.getAddressRequestsStatusMap(); return this.arrayHelper.sort([{ label: map[AddressRequestStatus.Approved], value: AddressRequestStatus.Approved }, { label: map[AddressRequestStatus.Rejected], value: AddressRequestStatus.Rejected }, { label: map[AddressRequestStatus.Pending], value: AddressRequestStatus.Pending }, { label: map[AddressRequestStatus.OnHold], value: AddressRequestStatus.OnHold }], 'label'); } constructor ( private logger: LogService, private i18n: I18nService, private notifier: NotifierService, private arrayHelper: ArrayHelpersService, private addressRequestResources: AddressRequestsResources, private addressFormatter: AddressFormatterService, private applicationFileService: ApplicationFileService, private fileService: FileService, private portal: PortalDeterminationService ) { super(); } async getAddressRequestRecords ( paginationOptions: PaginationOptions ) { const options = this.formatPaginationOptions(paginationOptions); const response = await this.addressRequestResources.getAddressRequests( options ); return { success: true, data: { records: response.records.map((record) => { const oldAddressString = this.addressFormatter.formatSimpleGrantsAddressWithBreaks( record.oldAddress, true ); const newAddressString = this.addressFormatter.formatSimpleGrantsAddressWithBreaks( record.newAddress, true ); const applicantAddressString = this.addressFormatter.formatSimpleGrantsAddressWithBreaks( record.applicantAddressInfo, true ); const orgAddressString = this.addressFormatter.formatSimpleGrantsAddressWithBreaks( record.organizationAddressInfo, true ); return { ...record, oldAddressString, newAddressString, applicantAddressString, orgAddressString }; }), recordCount: response.recordCount } }; } formatPaginationOptions ( paginationOptions: PaginationOptions ) { // Address Requests have a hidden && top level filter with the same column: // (addressRequestStatus) // so if they both exist in filter cols, make sure we only use the more specific one const statusFilters = paginationOptions.filterColumns.filter((filter) => { return filter.columnName === 'addressRequestStatus'; }); if (statusFilters.length === 2) { const indexToRemove = statusFilters.findIndex((filter) => { return filter.filters.length > 1; }); if (indexToRemove > -1) { paginationOptions = { ...paginationOptions, filterColumns: [ ...paginationOptions.filterColumns.slice(0, indexToRemove), ...paginationOptions.filterColumns.slice(indexToRemove + 1) ] }; } } const orgIdIndex = paginationOptions.orFilterColumns.findIndex((col) => { return col.columnName === 'organizationIdentification'; }); if (orgIdIndex > -1) { paginationOptions = { ...paginationOptions, orFilterColumns: [ ...paginationOptions.orFilterColumns.slice(0, orgIdIndex), { ...paginationOptions.orFilterColumns[orgIdIndex], filters: [ ...paginationOptions.orFilterColumns[orgIdIndex].filters.map((filter) => { filter.filterValue = (filter.filterValue + '').replace('-', ''); return filter; }) ] }, ...paginationOptions.orFilterColumns.slice(orgIdIndex + 1) ] }; } return paginationOptions; } async handleToggleHold ( addressRequestId: number, newStatus: AddressRequestStatus, comment: string ): Promise { try { await this.addressRequestResources.updateStatus( addressRequestId, newStatus, comment ); this.notifier.success(this.i18n.translate( 'GLOBAL:textSuccessfullyUpdatedAddressRequestStatus', {}, 'Successfully updated the address request status' )); return true; } catch (e) { this.logger.error(e); this.notifier.error(this.i18n.translate( 'GLOBAL:textErrorUpdatingAddressRequestStatus', {}, 'There was an error updating the address request status' )); return false; } } async getFilesForAddressRequest ( addressRequestId: number, applicationId: number ): Promise { const files = await this.addressRequestResources.getFilesForAddressRequest( addressRequestId, applicationId ); return files.map((file) => { const isRequest = file.fileType === FileType.APPLICANT_REQUEST; const fileTypeTranslated = this.i18n.translate( isRequest ? 'GLOBAL:textApplicantRequest' : 'GLOBAL:textApprovalDocument', {}, isRequest ? 'Applicant request' : 'Approval document' ); if (!file.fileName) { const details = this.applicationFileService.breakDownloadUrlDownToObject( file.url ); file.fileName = details.fileName; } return { ...file, fileTypeTranslated, urlNeedsDecoded: file.url?.includes('yourcausegrants') }; }); } async handleApproveRequest (payload: AddressRequestApproveApi) { try { await this.addressRequestResources.approveRequest(payload); this.notifier.success(this.i18n.translate( 'common:textSuccessApprovingAddressRequest', {}, 'Successfully approved the address request' )); } catch (e) { this.logger.error(e); this.notifier.error(this.i18n.translate( 'common:textErrorApprovingAddressRequest', {}, 'There was an error approving the address request' )); } } async handleRejectRequest (payload: AddressRequestRejectApi) { try { await this.addressRequestResources.rejectRequest(payload); this.notifier.success(this.i18n.translate( 'common:textSuccessRejectedAddressRequest', {}, 'Successfully rejected the address request' )); } catch (e) { this.logger.error(e); this.notifier.error(this.i18n.translate( 'common:textErrorRejectingAddressRequest', {}, 'There was an error rejecting the address request' )); } } uploadApprovalFile ( file: File, applicationId: number ) { return this.addressRequestResources.uploadApprovalFile( file, applicationId ); } async downloadAddressRequestFile ( url: string, applicationId: number ) { try { if (url) { const details = this.applicationFileService.breakDownloadUrlDownToObject(url); if (this.portal.isPlatform) { const fileInfo = await this.addressRequestResources.getPlatformUrlForAddressRequestFile( applicationId, +details.fileId ); await this.fileService.downloadUrlAs(fileInfo.accessUrl, details.fileName); } else { await this.applicationFileService.downloadFile( +details.applicationId, +details.fileId, details.fileName, +details.applicationFormId ); } } } catch (e) { this.logger.error(e); this.notifier.error(this.i18n.translate( 'CONFIG:textErrorDownloadingTheFile', {}, 'There was an error downloading the file' )); } } async uploadAddressRequestFile ( file: File, fileName: string, applicationId: number ): Promise { const fileId = await this.addressRequestResources.uploadAddressRequestFile( file, applicationId ); const locationBase = environment.isLocalhost ? 'yourcausegrantsqa.com' : environment.locationBase; const queryParams = { applicationId, fileId, fileName }; const query = Object.keys(queryParams) .map(key => key as keyof typeof queryParams) .map((key) => `${key}=${queryParams[key]}`) .join('&'); return { url:`https://${locationBase}/management/download-file?${query}`, fileUploadId: fileId }; } }