From 379812833e16ffd335fe05a637574db6fbd981c7 Mon Sep 17 00:00:00 2001 From: abradat Date: Mon, 9 Sep 2024 20:53:29 -0700 Subject: [PATCH 01/20] Add GIS subtask days to home page subtask table --- .../subtask-table.component.html | 11 +- .../subtask-table.component.scss | 6 +- .../subtask-table/subtask-table.component.ts | 7 +- .../apps/alcs/src/alcs/admin/admin.module.ts | 1 + .../admin/holiday/holiday.service.spec.ts | 23 ++++ .../src/alcs/admin/holiday/holiday.service.ts | 55 +++++++++ .../card/card-subtask/card-subtask.dto.ts | 1 + .../src/alcs/home/home.controller.spec.ts | 65 +++++++++++ .../alcs/src/alcs/home/home.controller.ts | 104 ++++++++++++++++-- .../apps/alcs/src/alcs/home/home.module.ts | 2 + services/apps/alcs/test/mocks/mockEntities.ts | 21 ++++ 11 files changed, 278 insertions(+), 18 deletions(-) diff --git a/alcs-frontend/src/app/features/home/subtask/subtask-table/subtask-table.component.html b/alcs-frontend/src/app/features/home/subtask/subtask-table/subtask-table.component.html index 353eca8f02..ea893b75dc 100644 --- a/alcs-frontend/src/app/features/home/subtask/subtask-table/subtask-table.component.html +++ b/alcs-frontend/src/app/features/home/subtask/subtask-table/subtask-table.component.html @@ -16,9 +16,7 @@ Type - - - - + - + + Subtask Days + + + Assignee @@ -91,7 +94,7 @@ task.type.code === CARD_SUBTASK_TYPE.GIS); + if (isGIS) { + const index = columns.indexOf('stage'); + columns.splice(index + 1, 0, 'subtaskDays'); + } return columns; } diff --git a/services/apps/alcs/src/alcs/admin/admin.module.ts b/services/apps/alcs/src/alcs/admin/admin.module.ts index 527e04bae7..819a9103a2 100644 --- a/services/apps/alcs/src/alcs/admin/admin.module.ts +++ b/services/apps/alcs/src/alcs/admin/admin.module.ts @@ -76,5 +76,6 @@ import { UnarchiveCardService } from './unarchive-card/unarchive-card.service'; ApplicationDecisionConditionTypesService, ConfigurationService, ], + exports: [HolidayService], }) export class AdminModule {} diff --git a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts index ae4072be31..592bad23f7 100644 --- a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts +++ b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts @@ -17,6 +17,8 @@ describe('HolidayService', () => { uuid: 'mock', }); + const RealDate = global.Date; + beforeEach(async () => { mockRepository = createMock(); @@ -143,4 +145,25 @@ describe('HolidayService', () => { expect(result[0]).toEqual('2020'); expect(mockRepository.query).toBeCalledTimes(1); }); + + it('should calculate business days of a given date without holidays', () => { + const res = service.calculateBusinessDays( + new Date('2024-09-09'), + new Date('2024-09-16'), + [], + ); + expect(res).toEqual(6); + }); + + it('should calculate business days of a given date with holidays', () => { + const holiday: HolidayEntity = new HolidayEntity({ + day: new Date('2024-09-09'), + }); + const res = service.calculateBusinessDays( + new Date('2024-09-09'), + new Date('2024-09-16'), + [holiday], + ); + expect(res).toEqual(5); + }); }); diff --git a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts index 7d15390048..fc9306922a 100644 --- a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts +++ b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts @@ -66,4 +66,59 @@ export class HolidayService { )) as { year: string }[]; return res.map((res) => res.year); } + + async fetchAllHolidays() { + return await this.holidayRepository + .createQueryBuilder('holiday') + .select('holiday.day') + .getMany(); + } + + calculateBusinessDays( + fromDate: Date, + toDate: Date, + holidays: HolidayEntity[], + ): number { + const formatDate = (date: Date): string => { + return date.toISOString().split('T')[0]; + }; + + const holidaysSet = new Set( + holidays.map((holiday) => formatDate(new Date(holiday.day))), + ); + + const isWeekend = (date: Date): boolean => { + const day = date.getDay(); + return day === 0 || day === 6; + }; + + const isBusinessDay = (date: Date): boolean => { + return isWeekend(date) || holidaysSet.has(formatDate(date)) + ? false + : true; + }; + + const addDays = (date: Date, days: number): Date => { + const result = new Date(date); + result.setDate(result.getDate() + days); + return result; + }; + + const differenceInDays = (startDate: Date, endDate: Date): number => { + const timeDiff = endDate.getTime() - startDate.getTime(); + return Math.ceil(timeDiff / (1000 * 60 * 60 * 24)); + }; + + const totalDays = differenceInDays(fromDate, toDate) + 1; + let businessDaysCount = 0; + + for (let i = 0; i < totalDays; i++) { + const currentDate = addDays(fromDate, i); + if (isBusinessDay(currentDate)) { + businessDaysCount++; + } + } + + return businessDaysCount; + } } diff --git a/services/apps/alcs/src/alcs/card/card-subtask/card-subtask.dto.ts b/services/apps/alcs/src/alcs/card/card-subtask/card-subtask.dto.ts index f555602d7e..99c2dc11d8 100644 --- a/services/apps/alcs/src/alcs/card/card-subtask/card-subtask.dto.ts +++ b/services/apps/alcs/src/alcs/card/card-subtask/card-subtask.dto.ts @@ -63,6 +63,7 @@ export class HomepageSubtaskDTO extends CardSubtaskDto { parentType: PARENT_TYPE; activeDays?: number; paused: boolean; + subtaskDays?: number; } export enum CARD_SUBTASK_TYPE { diff --git a/services/apps/alcs/src/alcs/home/home.controller.spec.ts b/services/apps/alcs/src/alcs/home/home.controller.spec.ts index 8ea1e2b566..5bb2a8a4c8 100644 --- a/services/apps/alcs/src/alcs/home/home.controller.spec.ts +++ b/services/apps/alcs/src/alcs/home/home.controller.spec.ts @@ -8,6 +8,7 @@ import { initApplicationMockEntity, initApplicationModificationMockEntity, initApplicationReconsiderationMockEntity, + initCardGISSubtaskMockEntity, initCardMockEntity, } from '../../../test/mocks/mockEntities'; import { mockKeyCloakProviders } from '../../../test/mocks/mockTypes'; @@ -35,6 +36,7 @@ import { Notification } from '../notification/notification.entity'; import { NotificationService } from '../notification/notification.service'; import { PlanningReferralService } from '../planning-review/planning-referral/planning-referral.service'; import { HomeController } from './home.controller'; +import { HolidayService } from '../admin/holiday/holiday.service'; describe('HomeController', () => { let controller: HomeController; @@ -48,6 +50,7 @@ describe('HomeController', () => { let mockNotificationService: DeepMocked; let mockPlanningReferralService: DeepMocked; let mockInquiryService: DeepMocked; + let mockHolidayService: DeepMocked; beforeEach(async () => { mockApplicationService = createMock(); @@ -60,6 +63,7 @@ describe('HomeController', () => { mockNotificationService = createMock(); mockPlanningReferralService = createMock(); mockInquiryService = createMock(); + mockHolidayService = createMock(); const module: TestingModule = await Test.createTestingModule({ imports: [ @@ -117,6 +121,10 @@ describe('HomeController', () => { provide: InquiryService, useValue: mockInquiryService, }, + { + provide: HolidayService, + useValue: mockHolidayService, + }, ApplicationProfile, ApplicationSubtaskProfile, UserProfile, @@ -253,6 +261,7 @@ describe('HomeController', () => { ]), ); + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); const res = await controller.getIncompleteSubtasksByType( CARD_SUBTASK_TYPE.GIS, ); @@ -265,6 +274,49 @@ describe('HomeController', () => { expect(res[0].title).toContain(mockApplication.applicant); expect(res[0].activeDays).toBe(activeDays); expect(res[0].paused).toBeTruthy(); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); + }); + + it('should call ApplicationService and map an Application and calculate GIS subtask days', async () => { + const mockApplication = initApplicationMockEntity(); + mockApplication.card!.subtasks = [ + initCardGISSubtaskMockEntity(mockApplication.card!), + ]; + const activeDays = 5; + mockApplicationService.getWithIncompleteSubtaskByType.mockResolvedValue([ + mockApplication, + ]); + mockApplicationTimeTrackingService.getPausedStatus.mockResolvedValue( + new Map([[mockApplication.uuid, true]]), + ); + mockApplicationTimeTrackingService.fetchActiveTimes.mockResolvedValue( + new Map([ + [ + mockApplication.uuid, + { + activeDays, + pausedDays: 0, + }, + ], + ]), + ); + + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); + mockHolidayService.calculateBusinessDays.mockReturnValue(0); + const res = await controller.getIncompleteSubtasksByType( + CARD_SUBTASK_TYPE.GIS, + ); + + expect(res.length).toEqual(1); + expect( + mockApplicationService.getWithIncompleteSubtaskByType, + ).toBeCalledTimes(1); + expect(res[0].title).toContain(mockApplication.fileNumber); + expect(res[0].title).toContain(mockApplication.applicant); + expect(res[0].activeDays).toBe(activeDays); + expect(res[0].paused).toBeTruthy(); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); + expect(mockHolidayService.calculateBusinessDays).toHaveBeenCalled(); }); it('should call Reconsideration Service and map it', async () => { @@ -273,6 +325,7 @@ describe('HomeController', () => { [mockReconsideration], ); + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); const res = await controller.getIncompleteSubtasksByType( CARD_SUBTASK_TYPE.GIS, ); @@ -287,6 +340,7 @@ describe('HomeController', () => { expect(res[0].title).toContain(mockReconsideration.application.applicant); expect(res[0].activeDays).toBeUndefined(); expect(res[0].paused).toBeFalsy(); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); }); // TODO: Fix when finishing planning reviews @@ -320,6 +374,7 @@ describe('HomeController', () => { mockApplicationModificationService.getWithIncompleteSubtaskByType.mockResolvedValue( [mockModification], ); + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); const res = await controller.getIncompleteSubtasksByType( CARD_SUBTASK_TYPE.GIS, @@ -334,6 +389,7 @@ describe('HomeController', () => { expect(res[0].title).toContain(mockModification.application.applicant); expect(res[0].activeDays).toBeUndefined(); expect(res[0].paused).toBeFalsy(); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); }); it('should call NOI Service and map it', async () => { @@ -357,6 +413,7 @@ describe('HomeController', () => { ], ]), ); + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); const res = await controller.getIncompleteSubtasksByType( CARD_SUBTASK_TYPE.PEER_REVIEW, @@ -370,6 +427,7 @@ describe('HomeController', () => { expect(res[0].title).toContain(mockNoi.fileNumber); expect(res[0].title).toContain(mockNoi.applicant); expect(res[0].activeDays).toBe(activeDays); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); }); it('should call NOI Modification Service and map it', async () => { @@ -383,6 +441,7 @@ describe('HomeController', () => { mockNoticeOfIntentModificationService.getWithIncompleteSubtaskByType.mockResolvedValue( [mockNoiModification], ); + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); const res = await controller.getIncompleteSubtasksByType( CARD_SUBTASK_TYPE.PEER_REVIEW, @@ -399,6 +458,7 @@ describe('HomeController', () => { expect(res[0].title).toContain( mockNoiModification.noticeOfIntent.applicant, ); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); }); it('should call Notification Service and map it', async () => { @@ -410,6 +470,7 @@ describe('HomeController', () => { mockNotificationService.getWithIncompleteSubtaskByType.mockResolvedValue([ mockNotification, ]); + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); const res = await controller.getIncompleteSubtasksByType( CARD_SUBTASK_TYPE.PEER_REVIEW, @@ -422,6 +483,7 @@ describe('HomeController', () => { expect(res[0].title).toContain(mockNotification.fileNumber); expect(res[0].title).toContain(mockNotification.applicant); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); }); it('should call Inquiry Service and map it', async () => { @@ -434,6 +496,8 @@ describe('HomeController', () => { mockInquiry, ]); + mockHolidayService.fetchAllHolidays.mockResolvedValue([]); + const res = await controller.getIncompleteSubtasksByType( CARD_SUBTASK_TYPE.PEER_REVIEW, ); @@ -445,6 +509,7 @@ describe('HomeController', () => { expect(res[0].title).toContain(mockInquiry.fileNumber); expect(res[0].title).toContain(mockInquiry.inquirerLastName); + expect(mockHolidayService.fetchAllHolidays).toHaveBeenCalled(); }); }); }); diff --git a/services/apps/alcs/src/alcs/home/home.controller.ts b/services/apps/alcs/src/alcs/home/home.controller.ts index 783a5d638c..785b74f76f 100644 --- a/services/apps/alcs/src/alcs/home/home.controller.ts +++ b/services/apps/alcs/src/alcs/home/home.controller.ts @@ -42,6 +42,7 @@ import { NotificationService } from '../notification/notification.service'; import { PlanningReferral } from '../planning-review/planning-referral/planning-referral.entity'; import { PlanningReferralService } from '../planning-review/planning-referral/planning-referral.service'; import { PlanningReferralDto } from '../planning-review/planning-review.dto'; +import { HolidayService } from '../admin/holiday/holiday.service'; const HIDDEN_CARD_STATUSES = [ CARD_STATUS.CANCELLED, @@ -63,6 +64,7 @@ export class HomeController { private notificationService: NotificationService, private planningReferralService: PlanningReferralService, private inquiryService: InquiryService, + private holidayService: HolidayService, ) {} @Get('/assigned') @@ -155,13 +157,13 @@ export class HomeController { await this.reconsiderationService.getWithIncompleteSubtaskByType( subtaskType, ); - const reconSubtasks = this.mapReconToDto(reconsiderationWithSubtasks); + const reconSubtasks = await this.mapReconToDto(reconsiderationWithSubtasks); const planningReferralsWithSubtasks = await this.planningReferralService.getWithIncompleteSubtaskByType( subtaskType, ); - const planningReferralSubtasks = this.mapPlanningReferralsToDtos( + const planningReferralSubtasks = await this.mapPlanningReferralsToDtos( planningReferralsWithSubtasks, ); @@ -169,7 +171,7 @@ export class HomeController { await this.modificationService.getWithIncompleteSubtaskByType( subtaskType, ); - const modificationSubtasks = this.mapModificationsToDtos( + const modificationSubtasks = await this.mapModificationsToDtos( modificationsWithSubtasks, ); @@ -184,7 +186,7 @@ export class HomeController { await this.noticeOfIntentModificationService.getWithIncompleteSubtaskByType( subtaskType, ); - const noiModificationsSubtasks = this.mapNoiModificationsToDtos( + const noiModificationsSubtasks = await this.mapNoiModificationsToDtos( noiModificationsWithSubtasks, ); @@ -193,14 +195,16 @@ export class HomeController { subtaskType, ); - const notificationSubtasks = this.mapNotificationsToDtos( + const notificationSubtasks = await this.mapNotificationsToDtos( notificationsWithSubtasks, ); const inquiriesWIthSubtasks = await this.inquiryService.getWithIncompleteSubtaskByType(subtaskType); - const inquirySubtasks = this.mapInquiriesToDtos(inquiriesWIthSubtasks); + const inquirySubtasks = await this.mapInquiriesToDtos( + inquiriesWIthSubtasks, + ); return [ ...noticeOfIntentSubtasks, @@ -214,8 +218,9 @@ export class HomeController { ]; } - private mapReconToDto(recons: ApplicationReconsideration[]) { + private async mapReconToDto(recons: ApplicationReconsideration[]) { const result: HomepageSubtaskDTO[] = []; + const holidays = await this.holidayService.fetchAllHolidays(); for (const recon of recons) { if (!recon.card) { continue; @@ -233,6 +238,14 @@ export class HomeController { title: `${recon.application.fileNumber} (${recon.application.applicant})`, appType: recon.application.type, parentType: PARENT_TYPE.RECONSIDERATION, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } @@ -244,6 +257,7 @@ export class HomeController { await this.timeService.fetchActiveTimes(applications); const appPausedMap = await this.timeService.getPausedStatus(applications); + const holidays = await this.holidayService.fetchAllHolidays(); const result: HomepageSubtaskDTO[] = []; for (const application of applications) { if (!application.card) { @@ -264,14 +278,25 @@ export class HomeController { title: `${application.fileNumber} (${application.applicant})`, appType: application.type, parentType: PARENT_TYPE.APPLICATION, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } return result; } - private mapPlanningReferralsToDtos(planningReferrals: PlanningReferral[]) { + private async mapPlanningReferralsToDtos( + planningReferrals: PlanningReferral[], + ) { const result: HomepageSubtaskDTO[] = []; + const holidays = await this.holidayService.fetchAllHolidays(); for (const planningReferral of planningReferrals) { for (const subtask of planningReferral.card.subtasks) { result.push({ @@ -285,6 +310,14 @@ export class HomeController { title: `${planningReferral.planningReview.fileNumber} (${planningReferral.planningReview.documentName})`, parentType: PARENT_TYPE.PLANNING_REVIEW, appType: planningReferral.planningReview.type, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } @@ -294,6 +327,7 @@ export class HomeController { private async mapNoticeOfIntentToDtos(noticeOfIntents: NoticeOfIntent[]) { const uuids = noticeOfIntents.map((noi) => noi.uuid); const timeMap = await this.noticeOfIntentService.getTimes(uuids); + const holidays = await this.holidayService.fetchAllHolidays(); const result: HomepageSubtaskDTO[] = []; for (const noticeOfIntent of noticeOfIntents) { @@ -312,6 +346,14 @@ export class HomeController { paused: false, title: `${noticeOfIntent.fileNumber} (${noticeOfIntent.applicant})`, parentType: PARENT_TYPE.NOTICE_OF_INTENT, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } @@ -319,8 +361,11 @@ export class HomeController { return result; } - private mapModificationsToDtos(modifications: ApplicationModification[]) { + private async mapModificationsToDtos( + modifications: ApplicationModification[], + ) { const result: HomepageSubtaskDTO[] = []; + const holidays = await this.holidayService.fetchAllHolidays(); for (const modification of modifications) { if (!modification.card) { continue; @@ -337,16 +382,25 @@ export class HomeController { title: `${modification.application.fileNumber} (${modification.application.applicant})`, appType: modification.application.type, parentType: PARENT_TYPE.MODIFICATION, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } return result; } - private mapNoiModificationsToDtos( + private async mapNoiModificationsToDtos( modifications: NoticeOfIntentModification[], ) { const result: HomepageSubtaskDTO[] = []; + const holidays = await this.holidayService.fetchAllHolidays(); for (const modification of modifications) { if (!modification.card) { continue; @@ -362,14 +416,23 @@ export class HomeController { paused: false, title: `${modification.noticeOfIntent.fileNumber} (${modification.noticeOfIntent.applicant})`, parentType: PARENT_TYPE.MODIFICATION, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } return result; } - private mapNotificationsToDtos(notifications: Notification[]) { + private async mapNotificationsToDtos(notifications: Notification[]) { const result: HomepageSubtaskDTO[] = []; + const holidays = await this.holidayService.fetchAllHolidays(); for (const notification of notifications) { if (notification.card) { for (const subtask of notification.card.subtasks) { @@ -384,6 +447,14 @@ export class HomeController { title: `${notification.fileNumber} (${notification.applicant})`, parentType: PARENT_TYPE.NOTIFICATION, appType: notification.type, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } @@ -391,8 +462,9 @@ export class HomeController { return result; } - private mapInquiriesToDtos(inquiries: Inquiry[]) { + private async mapInquiriesToDtos(inquiries: Inquiry[]) { const result: HomepageSubtaskDTO[] = []; + const holidays = await this.holidayService.fetchAllHolidays(); for (const inquiry of inquiries) { if (inquiry.card) { for (const subtask of inquiry.card.subtasks) { @@ -409,6 +481,14 @@ export class HomeController { })`, parentType: PARENT_TYPE.INQUIRY, appType: inquiry.type, + subtaskDays: + subtask.type.code === CARD_SUBTASK_TYPE.GIS + ? this.holidayService.calculateBusinessDays( + subtask.createdAt, + new Date(), + holidays, + ) + : 0, }); } } diff --git a/services/apps/alcs/src/alcs/home/home.module.ts b/services/apps/alcs/src/alcs/home/home.module.ts index 42fef95051..0dc9da6ae5 100644 --- a/services/apps/alcs/src/alcs/home/home.module.ts +++ b/services/apps/alcs/src/alcs/home/home.module.ts @@ -9,6 +9,7 @@ import { NoticeOfIntentModule } from '../notice-of-intent/notice-of-intent.modul import { NotificationModule } from '../notification/notification.module'; import { PlanningReviewModule } from '../planning-review/planning-review.module'; import { HomeController } from './home.controller'; +import { AdminModule } from '../admin/admin.module'; @Module({ imports: [ @@ -20,6 +21,7 @@ import { HomeController } from './home.controller'; NoticeOfIntentDecisionModule, NotificationModule, InquiryModule, + AdminModule, ], providers: [ApplicationSubtaskProfile], controllers: [HomeController], diff --git a/services/apps/alcs/test/mocks/mockEntities.ts b/services/apps/alcs/test/mocks/mockEntities.ts index c7de433452..a6bbaf7bd1 100644 --- a/services/apps/alcs/test/mocks/mockEntities.ts +++ b/services/apps/alcs/test/mocks/mockEntities.ts @@ -52,6 +52,26 @@ const initCardSubtaskMockEntity = (card: Card, uuid?: string): CardSubtask => { return subtask; }; +const initCardGISSubtaskMockEntity = ( + card: Card, + uuid?: string, +): CardSubtask => { + const subtask = new CardSubtask(); + subtask.assignee = initUserMockEntity(); + subtask.uuid = uuid ?? '11111'; + subtask.assigneeUuid = subtask.assignee.uuid; + subtask.createdAt = new Date(1, 1, 1, 1, 1, 1, 1); + subtask.auditDeletedDateAt = new Date(1, 1, 1, 1, 1, 1, 1); + subtask.auditCreatedAt = new Date(1, 1, 1, 1, 1, 1, 1); + subtask.auditUpdatedAt = new Date(1, 1, 1, 1, 1, 1, 1); + subtask.card = card; + subtask.type = new CardSubtaskType(); + subtask.type.backgroundColor = 'fake-bg-color'; + subtask.type.textColor = 'fake-color'; + subtask.type.code = 'GIS'; + return subtask; +}; + const initBoardMockEntity = (): Board => { const board = new Board(); board.uuid = 'fake-uuid'; @@ -334,6 +354,7 @@ export { initApplicationMeetingMock, initCardMockEntity, initCardSubtaskMockEntity, + initCardGISSubtaskMockEntity, initBoardMockEntity, initCardTypeMockEntity, initApplicationDecisionMock, From a7ae0969b15a093da81ee1992150857b7f8d39ba Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 08:29:20 -0700 Subject: [PATCH 02/20] Remove unnecessary variable --- .../apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts index 592bad23f7..7090c8ad92 100644 --- a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts +++ b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.spec.ts @@ -17,8 +17,6 @@ describe('HolidayService', () => { uuid: 'mock', }); - const RealDate = global.Date; - beforeEach(async () => { mockRepository = createMock(); From bdb102352696559859774b83ef7d92d5ca7294ea Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 11:16:20 -0700 Subject: [PATCH 03/20] Add decision detail to commissioner backend --- .../application-decision-v2.service.ts | 4 +++ .../commissioner.controller.spec.ts | 7 ++++ .../commissioner/commissioner.controller.ts | 14 ++++++++ .../src/alcs/commissioner/commissioner.dto.ts | 33 +++++++++++++++++++ ...lication-decision-v2.automapper.profile.ts | 11 +++++++ 5 files changed, 69 insertions(+) diff --git a/services/apps/alcs/src/alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service.ts b/services/apps/alcs/src/alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service.ts index d416c55d1a..8248bb6362 100644 --- a/services/apps/alcs/src/alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service.ts +++ b/services/apps/alcs/src/alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service.ts @@ -84,6 +84,10 @@ export class ApplicationDecisionV2Service { }); } + async getForCommissioner(fileNumber: string) { + return await this.getForPortal(fileNumber); + } + async getByAppFileNumber(number: string) { const application = await this.applicationService.getOrFail(number); diff --git a/services/apps/alcs/src/alcs/commissioner/commissioner.controller.spec.ts b/services/apps/alcs/src/alcs/commissioner/commissioner.controller.spec.ts index cd9fd532bf..078beed812 100644 --- a/services/apps/alcs/src/alcs/commissioner/commissioner.controller.spec.ts +++ b/services/apps/alcs/src/alcs/commissioner/commissioner.controller.spec.ts @@ -15,6 +15,7 @@ import { ApplicationReconsiderationService } from '../application-decision/appli import { PlanningReview } from '../planning-review/planning-review.entity'; import { PlanningReviewService } from '../planning-review/planning-review.service'; import { CommissionerController } from './commissioner.controller'; +import { ApplicationDecisionV2Service } from '../application-decision/application-decision-v2/application-decision/application-decision-v2.service'; describe('CommissionerController', () => { let controller: CommissionerController; @@ -23,6 +24,7 @@ describe('CommissionerController', () => { let mockModificationService: DeepMocked; let mockTrackingService: DeepMocked; let mockPlanningReviewService: DeepMocked; + let mockDecisionService: DeepMocked; let mockRequest; const fileNumber = 'fake-file'; @@ -33,6 +35,7 @@ describe('CommissionerController', () => { mockModificationService = createMock(); mockTrackingService = createMock(); mockPlanningReviewService = createMock(); + mockDecisionService = createMock(); const module: TestingModule = await Test.createTestingModule({ imports: [ @@ -62,6 +65,10 @@ describe('CommissionerController', () => { provide: PlanningReviewService, useValue: mockPlanningReviewService, }, + { + provide: ApplicationDecisionV2Service, + useValue: mockDecisionService, + }, { provide: ClsService, useValue: {}, diff --git a/services/apps/alcs/src/alcs/commissioner/commissioner.controller.ts b/services/apps/alcs/src/alcs/commissioner/commissioner.controller.ts index 0cbb0338af..a5ae407762 100644 --- a/services/apps/alcs/src/alcs/commissioner/commissioner.controller.ts +++ b/services/apps/alcs/src/alcs/commissioner/commissioner.controller.ts @@ -15,8 +15,11 @@ import { PlanningReviewDto } from '../planning-review/planning-review.dto'; import { PlanningReviewService } from '../planning-review/planning-review.service'; import { CommissionerApplicationDto, + CommissionerDecisionDto, CommissionerPlanningReviewDto, } from './commissioner.dto'; +import { ApplicationDecisionV2Service } from '../application-decision/application-decision-v2/application-decision/application-decision-v2.service'; +import { ApplicationDecision } from '../application-decision/application-decision.entity'; @Controller('commissioner') @ApiOAuth2(config.get('KEYCLOAK.SCOPES')) @@ -28,6 +31,7 @@ export class CommissionerController { private modificationService: ApplicationModificationService, private reconsiderationService: ApplicationReconsiderationService, private trackingService: TrackingService, + private decisionService: ApplicationDecisionV2Service, @InjectMapper() private mapper: Mapper, ) {} @@ -50,6 +54,16 @@ export class CommissionerController { ApplicationDto, CommissionerApplicationDto, ); + + if (application.decisionDate) { + const decisions = + await this.decisionService.getForCommissioner(fileNumber); + finalMap[0].decisions = this.mapper.mapArray( + decisions, + ApplicationDecision, + CommissionerDecisionDto, + ); + } const hasApprovedOrPendingModification = modifications.reduce( (showLabel, modification) => { return modification.reviewOutcome.code !== 'REF'; diff --git a/services/apps/alcs/src/alcs/commissioner/commissioner.dto.ts b/services/apps/alcs/src/alcs/commissioner/commissioner.dto.ts index d2be50f242..d778c99b61 100644 --- a/services/apps/alcs/src/alcs/commissioner/commissioner.dto.ts +++ b/services/apps/alcs/src/alcs/commissioner/commissioner.dto.ts @@ -4,6 +4,11 @@ import { LocalGovernmentDto } from '../local-government/local-government.dto'; import { ApplicationRegionDto } from '../code/application-code/application-region/application-region.dto'; import { ApplicationTypeDto } from '../code/application-code/application-type/application-type.dto'; import { PlanningReviewTypeDto } from '../planning-review/planning-review.dto'; +import { + ApplicationDecisionOutcomeCodeDto, + DecisionDocumentDto, +} from '../application-decision/application-decision-v2/application-decision/application-decision.dto'; +import { LinkedResolutionDto } from '../notice-of-intent-decision/notice-of-intent-decision.dto'; export class CommissionerApplicationDto { @AutoMap() @@ -35,6 +40,9 @@ export class CommissionerApplicationDto { hasRecons: boolean; hasModifications: boolean; + + @AutoMap() + decisions?: CommissionerDecisionDto[]; } export class CommissionerPlanningReviewDto { @@ -59,3 +67,28 @@ export class CommissionerPlanningReviewDto { @AutoMap() legacyId?: string; } + +export class CommissionerDecisionDto { + @AutoMap() + uuid: string; + + date: number; + + @AutoMap(() => ApplicationDecisionOutcomeCodeDto) + outcome: ApplicationDecisionOutcomeCodeDto; + + @AutoMap(() => String) + decisionDescription: string; + + @AutoMap(() => String) + resolutionNumber: number; + + @AutoMap(() => String) + resolutionYear: number; + + @AutoMap(() => [DecisionDocumentDto]) + documents: DecisionDocumentDto[]; + + @AutoMap(() => Boolean) + isSubjectToConditions: boolean; +} diff --git a/services/apps/alcs/src/common/automapper/application-decision-v2.automapper.profile.ts b/services/apps/alcs/src/common/automapper/application-decision-v2.automapper.profile.ts index d1456b8c62..1b12dc40a0 100644 --- a/services/apps/alcs/src/common/automapper/application-decision-v2.automapper.profile.ts +++ b/services/apps/alcs/src/common/automapper/application-decision-v2.automapper.profile.ts @@ -39,6 +39,7 @@ import { NaruSubtype } from '../../portal/application-submission/naru-subtype/na import { ApplicationDecisionConditionToComponentLotDto } from '../../alcs/application-decision/application-condition-to-component-lot/application-condition-to-component-lot.controller.dto'; import { ApplicationDecisionConditionToComponentLot } from '../../alcs/application-decision/application-condition-to-component-lot/application-decision-condition-to-component-lot.entity'; import { ApplicationDecisionConditionComponentPlanNumber } from '../../alcs/application-decision/application-decision-component-to-condition/application-decision-component-to-condition-plan-number.entity'; +import { CommissionerDecisionDto } from '../../alcs/commissioner/commissioner.dto'; @Injectable() export class ApplicationDecisionProfile extends AutomapperProfile { @@ -307,6 +308,16 @@ export class ApplicationDecisionProfile extends AutomapperProfile { ), ); + createMap( + mapper, + ApplicationDecision, + CommissionerDecisionDto, + forMember( + (ad) => ad.date, + mapFrom((a) => a.date?.getTime()), + ), + ); + createMap( mapper, ApplicationDecisionComponentLot, From 2ce8b5ae2722343f45915752ec6388d545e7be90 Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 12:11:49 -0700 Subject: [PATCH 04/20] Fix timezone difference issue --- .../alcs/src/alcs/admin/holiday/holiday.service.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts index fc9306922a..fd10edbb40 100644 --- a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts +++ b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts @@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Between, FindOptionsWhere, Repository } from 'typeorm'; import { HolidayCreateDto, HolidayUpdateDto } from './holiday.dto'; import { HolidayEntity } from './holiday.entity'; +import { getStartOfDayToPacific } from '../../../utils/pacific-date-time-helper'; @Injectable() export class HolidayService { @@ -105,11 +106,20 @@ export class HolidayService { }; const differenceInDays = (startDate: Date, endDate: Date): number => { - const timeDiff = endDate.getTime() - startDate.getTime(); - return Math.ceil(timeDiff / (1000 * 60 * 60 * 24)); + const timeDiff = + getStartOfDayToPacific(endDate.getTime()).getTime() - + getStartOfDayToPacific(startDate.getTime()).getTime(); + return Math.floor(timeDiff / (1000 * 60 * 60 * 24)); }; + console.log(fromDate); + console.log(toDate); + + console.log(getStartOfDayToPacific(fromDate.getTime())); + const totalDays = differenceInDays(fromDate, toDate) + 1; + console.log(totalDays); + console.log('======='); let businessDaysCount = 0; for (let i = 0; i < totalDays; i++) { From 221f3db4cc7243a70b5a4206b8eef259b38d2d34 Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 12:13:01 -0700 Subject: [PATCH 05/20] Remove log --- .../apps/alcs/src/alcs/admin/holiday/holiday.service.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts index fd10edbb40..2d02efbe55 100644 --- a/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts +++ b/services/apps/alcs/src/alcs/admin/holiday/holiday.service.ts @@ -112,14 +112,7 @@ export class HolidayService { return Math.floor(timeDiff / (1000 * 60 * 60 * 24)); }; - console.log(fromDate); - console.log(toDate); - - console.log(getStartOfDayToPacific(fromDate.getTime())); - const totalDays = differenceInDays(fromDate, toDate) + 1; - console.log(totalDays); - console.log('======='); let businessDaysCount = 0; for (let i = 0; i < totalDays; i++) { From 3794439d52c3c6ae91655a67cb62b1afa316db0b Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 13:40:47 -0700 Subject: [PATCH 06/20] Add commissioner decision component and DTO --- .../application/decisions/decisions.component.html | 1 + .../application/decisions/decisions.component.scss | 3 +++ .../application/decisions/decisions.component.ts | 14 ++++++++++++++ .../app/services/commissioner/commissioner.dto.ts | 13 +++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html create mode 100644 alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss create mode 100644 alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts diff --git a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html new file mode 100644 index 0000000000..f912f779cd --- /dev/null +++ b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html @@ -0,0 +1 @@ +

decisions works!

, diff --git a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss new file mode 100644 index 0000000000..5d4e87f30f --- /dev/null +++ b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts new file mode 100644 index 0000000000..3cbdfc84b4 --- /dev/null +++ b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts @@ -0,0 +1,14 @@ +import { ChangeDetectionStrategy, Component, Input, type OnInit } from '@angular/core'; +import { CommissionerDecisionDto } from '../../../../services/commissioner/commissioner.dto'; +import { ApplicationDocumentService } from '../../../../services/application/application-document/application-document.service'; + +@Component({ + selector: 'app-decisions', + templateUrl: './decisions.component.html', + styleUrl: './decisions.component.scss', +}) +export class DecisionsComponent implements OnInit { + @Input() applicationDecisions: CommissionerDecisionDto[] = []; + constructor(private decisionService: ApplicationDocumentService) {} + ngOnInit(): void {} +} diff --git a/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts b/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts index 604ba26fc5..a21ff826c4 100644 --- a/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts +++ b/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts @@ -1,6 +1,8 @@ +import { BaseCodeDto } from 'src/app/shared/dto/base.dto'; import { ApplicationRegionDto, ApplicationTypeDto } from '../application/application-code.dto'; import { ApplicationLocalGovernmentDto } from '../application/application-local-government/application-local-government.dto'; import { PlanningReviewTypeDto } from '../planning-review/planning-review.dto'; +import { ApplicationDocumentDto } from '../application/application-document/application-document.dto'; export interface CommissionerApplicationDto { fileNumber: string; @@ -25,3 +27,14 @@ export interface CommissionerPlanningReviewDto { localGovernment: ApplicationLocalGovernmentDto; legacyId?: string; } + +export interface CommissionerDecisionDto { + uuid: string; + date: number; + outcome: BaseCodeDto; + decisionDescription: string; + resolutionNumber: number; + resolutionYear: number; + documents: ApplicationDocumentDto[]; + isSubjectToConditions: boolean; +} From 2c47d2eee4bafa952333fd1591fa9682158dff24 Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 16:00:40 -0700 Subject: [PATCH 07/20] Add functions.scss --- alcs-frontend/src/styles/functions.scss | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 alcs-frontend/src/styles/functions.scss diff --git a/alcs-frontend/src/styles/functions.scss b/alcs-frontend/src/styles/functions.scss new file mode 100644 index 0000000000..4c6a80f5dc --- /dev/null +++ b/alcs-frontend/src/styles/functions.scss @@ -0,0 +1,10 @@ +@use 'sass:math'; + +@function rem($pixels, $context: 16) { + @return math.div($pixels, $context) * 1rem; +} + +$tabletBreakpoint: rem(481); +$desktopBreakpoint: rem(769); +$midBreakpoint: rem(669); +$minWidth: rem(300); From d8f8280e29dba3c2a75475cc9323def3af22b476 Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 16:01:14 -0700 Subject: [PATCH 08/20] Rename commissioner decision component and Add to commissioner's application page --- .../commissioner-application.component.html | 4 ++ .../commissioner-decisions.component.html | 45 +++++++++++++++++ .../commissioner-decisions.component.scss | 49 +++++++++++++++++++ .../commissioner-decisions.component.ts | 19 +++++++ .../decisions/decisions.component.html | 1 - .../decisions/decisions.component.scss | 3 -- .../decisions/decisions.component.ts | 14 ------ .../commissioner/commissioner.module.ts | 5 +- .../application-document.dto.ts | 1 + .../services/commissioner/commissioner.dto.ts | 1 + 10 files changed, 122 insertions(+), 20 deletions(-) create mode 100644 alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.html create mode 100644 alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss create mode 100644 alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.ts delete mode 100644 alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html delete mode 100644 alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss delete mode 100644 alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts diff --git a/alcs-frontend/src/app/features/commissioner/application/commissioner-application.component.html b/alcs-frontend/src/app/features/commissioner/application/commissioner-application.component.html index 8984d0890b..ed29539a60 100644 --- a/alcs-frontend/src/app/features/commissioner/application/commissioner-application.component.html +++ b/alcs-frontend/src/app/features/commissioner/application/commissioner-application.component.html @@ -2,6 +2,10 @@
+ +

Decision #{{ applicationDecisions.length - index }}

+
+
+
Decision Date
+ {{ decision.date | momentFormat }} +
+ +
+
Resolution Number
+ #{{ decision.resolutionNumber }}/{{ decision.resolutionYear }} +
+ +
+
Decision Summary
+ {{ decision.decisionDescription }} +
+ +
+
Decision Document
+
+
+ {{ document.fileName }} +  ({{ document.fileSize! | filesize }}) +
+ +
+
+ +
+
{{ document.fileSize! | filesize }}
+ +
+
+
+
+
diff --git a/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss b/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss new file mode 100644 index 0000000000..5904a02cb2 --- /dev/null +++ b/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss @@ -0,0 +1,49 @@ +@use '../../../../../styles/functions.scss' as *; +@use '../../../../../styles/colors.scss'; + +.decision-table { + padding: rem(8); + margin: rem(12) 0 rem(20) 0; + background-color: colors.$grey-light; + display: grid; + grid-row-gap: rem(24); + grid-column-gap: rem(16); + grid-template-columns: 100%; + word-wrap: break-word; + hyphens: auto; + + @media screen and (min-width: $tabletBreakpoint) { + padding: rem(16); + margin: rem(24) 0 rem(40) 0; + grid-template-columns: 49% 49%; + + .full-width { + grid-column: 1/3; + } + } +} + +.document { + display: none; + padding: rem(9) rem(16); + border-radius: rem(4); + border: rem(1) solid colors.$grey; + background: colors.$white; + margin: rem(8) 0; + + @media screen and (min-width: $tabletBreakpoint) { + display: flex; + } +} + +.responsive { + display: block; + + @media screen and (min-width: $tabletBreakpoint) { + display: none; + } +} + +.document-name { + padding: rem(6) 0; +} diff --git a/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.ts b/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.ts new file mode 100644 index 0000000000..52ba3e23cc --- /dev/null +++ b/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.ts @@ -0,0 +1,19 @@ +import { Component, Input, type OnInit } from '@angular/core'; +import { CommissionerDecisionDto } from '../../../../services/commissioner/commissioner.dto'; +import { ApplicationDocumentService } from '../../../../services/application/application-document/application-document.service'; +import { ApplicationDecisionV2Service } from '../../../../services/application/decision/application-decision-v2/application-decision-v2.service'; +import { ApplicationDocumentDto } from '../../../../services/application/application-document/application-document.dto'; + +@Component({ + selector: 'app-commissioner-decisions', + templateUrl: './commissioner-decisions.component.html', + styleUrl: './commissioner-decisions.component.scss', +}) +export class CommissionerDecisionsComponent { + @Input() applicationDecisions: CommissionerDecisionDto[] = []; + constructor(private decisionService: ApplicationDecisionV2Service) {} + + async openFile(decision: CommissionerDecisionDto, file: ApplicationDocumentDto) { + const res = await this.decisionService.downloadFile(decision.uuid, file.uuid, file.fileName); + } +} diff --git a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html deleted file mode 100644 index f912f779cd..0000000000 --- a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.html +++ /dev/null @@ -1 +0,0 @@ -

decisions works!

, diff --git a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss deleted file mode 100644 index 5d4e87f30f..0000000000 --- a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -:host { - display: block; -} diff --git a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts b/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts deleted file mode 100644 index 3cbdfc84b4..0000000000 --- a/alcs-frontend/src/app/features/commissioner/application/decisions/decisions.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input, type OnInit } from '@angular/core'; -import { CommissionerDecisionDto } from '../../../../services/commissioner/commissioner.dto'; -import { ApplicationDocumentService } from '../../../../services/application/application-document/application-document.service'; - -@Component({ - selector: 'app-decisions', - templateUrl: './decisions.component.html', - styleUrl: './decisions.component.scss', -}) -export class DecisionsComponent implements OnInit { - @Input() applicationDecisions: CommissionerDecisionDto[] = []; - constructor(private decisionService: ApplicationDocumentService) {} - ngOnInit(): void {} -} diff --git a/alcs-frontend/src/app/features/commissioner/commissioner.module.ts b/alcs-frontend/src/app/features/commissioner/commissioner.module.ts index eb94ab63d7..3908837f2b 100644 --- a/alcs-frontend/src/app/features/commissioner/commissioner.module.ts +++ b/alcs-frontend/src/app/features/commissioner/commissioner.module.ts @@ -5,6 +5,7 @@ import { SharedModule } from '../../shared/shared.module'; import { PlanningReviewModule } from '../planning-review/planning-review.module'; import { CommissionerApplicationComponent } from './application/commissioner-application.component'; import { CommissionerPlanningReviewComponent } from './planning-review/commissioner-planning-review.component'; +import { CommissionerDecisionsComponent } from './application/commissioner-decisions/commissioner-decisions.component'; const routes: Routes = [ { @@ -18,7 +19,7 @@ const routes: Routes = [ ]; @NgModule({ - declarations: [CommissionerApplicationComponent, CommissionerPlanningReviewComponent], - imports: [CommonModule, SharedModule, PlanningReviewModule, RouterModule.forChild(routes)], + declarations: [CommissionerApplicationComponent, CommissionerPlanningReviewComponent, CommissionerDecisionsComponent], + imports: [CommonModule, SharedModule, PlanningReviewModule, RouterModule.forChild(routes), SharedModule], }) export class CommissionerModule {} diff --git a/alcs-frontend/src/app/services/application/application-document/application-document.dto.ts b/alcs-frontend/src/app/services/application/application-document/application-document.dto.ts index 5a72d5ed32..a84c1ef82f 100644 --- a/alcs-frontend/src/app/services/application/application-document/application-document.dto.ts +++ b/alcs-frontend/src/app/services/application/application-document/application-document.dto.ts @@ -18,6 +18,7 @@ export interface ApplicationDocumentDto { uploadedBy: string; uploadedAt: number; evidentiaryRecordSorting?: number; + fileSize?: number; } export interface UpdateDocumentDto { diff --git a/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts b/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts index a21ff826c4..07f52d7e00 100644 --- a/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts +++ b/alcs-frontend/src/app/services/commissioner/commissioner.dto.ts @@ -16,6 +16,7 @@ export interface CommissionerApplicationDto { hasRecons: boolean; hasModifications: boolean; legacyId?: string; + decisions?: CommissionerDecisionDto[]; } export interface CommissionerPlanningReviewDto { From 6e65bcd2f3c004d1953d6811647317b65287faf2 Mon Sep 17 00:00:00 2001 From: abradat Date: Tue, 10 Sep 2024 16:55:22 -0700 Subject: [PATCH 09/20] Remove unnecessary functions.scss --- .../commissioner-decisions.component.scss | 42 +++++++------------ alcs-frontend/src/styles/functions.scss | 10 ----- 2 files changed, 14 insertions(+), 38 deletions(-) delete mode 100644 alcs-frontend/src/styles/functions.scss diff --git a/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss b/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss index 5904a02cb2..a06b72eceb 100644 --- a/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss +++ b/alcs-frontend/src/app/features/commissioner/application/commissioner-decisions/commissioner-decisions.component.scss @@ -1,49 +1,35 @@ -@use '../../../../../styles/functions.scss' as *; @use '../../../../../styles/colors.scss'; .decision-table { - padding: rem(8); - margin: rem(12) 0 rem(20) 0; + padding: 16px; + margin: 24px 0 40px 0; background-color: colors.$grey-light; display: grid; - grid-row-gap: rem(24); - grid-column-gap: rem(16); + grid-row-gap: 24px; + grid-column-gap: 16px; grid-template-columns: 100%; word-wrap: break-word; hyphens: auto; - - @media screen and (min-width: $tabletBreakpoint) { - padding: rem(16); - margin: rem(24) 0 rem(40) 0; - grid-template-columns: 49% 49%; - - .full-width { - grid-column: 1/3; - } + grid-template-columns: 49% 49%; + .full-width { + grid-column: 1/3; } } .document { display: none; - padding: rem(9) rem(16); - border-radius: rem(4); - border: rem(1) solid colors.$grey; + padding: 9px 16px; + border-radius: 4px; + border: 1px solid colors.$grey; background: colors.$white; - margin: rem(8) 0; - - @media screen and (min-width: $tabletBreakpoint) { - display: flex; - } + margin: 8px 0; + display: flex; } .responsive { - display: block; - - @media screen and (min-width: $tabletBreakpoint) { - display: none; - } + display: none; } .document-name { - padding: rem(6) 0; + padding: 6px 0; } diff --git a/alcs-frontend/src/styles/functions.scss b/alcs-frontend/src/styles/functions.scss deleted file mode 100644 index 4c6a80f5dc..0000000000 --- a/alcs-frontend/src/styles/functions.scss +++ /dev/null @@ -1,10 +0,0 @@ -@use 'sass:math'; - -@function rem($pixels, $context: 16) { - @return math.div($pixels, $context) * 1rem; -} - -$tabletBreakpoint: rem(481); -$desktopBreakpoint: rem(769); -$midBreakpoint: rem(669); -$minWidth: rem(300); From 93b1134d8c4343e0922a8073acc1466c0c400d88 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:44:48 -0700 Subject: [PATCH 10/20] Conver to plain HTML email templates with bare-bones templates --- .../application-submission.controller.ts | 4 +- .../application/application.controller.ts | 4 +- .../notice-of-intent.controller.ts | 4 +- ...pplication-submission-review.controller.ts | 20 +- .../application-submission.controller.ts | 32 ++- ...tice-of-intent-submission-draft.service.ts | 4 +- .../notice-of-intent-submission.controller.ts | 10 +- .../notification-submission.service.ts | 7 +- .../providers/email/status-email.service.ts | 12 +- .../decision-emails.consumer.ts | 12 +- .../status-emails/status-emails.consumer.ts | 12 +- .../decision-emails.consumer.ts | 4 +- .../email-template.service.spec.ts | 22 --- .../email-template.service.ts | 24 --- .../emails/cancelled/application.template.ts | 56 ++---- services/templates/emails/cancelled/index.ts | 2 - .../cancelled/notice-of-intent.template.ts | 56 ++---- .../decision-released/application.template.ts | 93 +++------ .../emails/decision-released/index.ts | 2 - .../notice-of-intent.template.ts | 93 +++------ services/templates/emails/index.ts | 13 ++ .../notifications/srw-notice.template.ts | 115 +++-------- .../emails/partials/footer.template.ts | 20 +- .../emails/partials/header.template.ts | 33 ++-- services/templates/emails/partials/index.ts | 4 - .../partials/notification-only.template.ts | 6 +- .../emails/partials/portal-button.template.ts | 17 +- .../emails/refused-to-forward.template.ts | 64 ++---- .../return-to-lfng/application.template.ts | 56 ++---- .../templates/emails/return-to-lfng/index.ts | 1 - .../emails/returned-as-incomplete.template.ts | 64 ++---- .../submitted-to-alc/application.template.ts | 182 ++++++++---------- .../cove-applicant.template.ts | 72 ++----- .../emails/submitted-to-alc/index.ts | 5 - .../no-review-government.template.ts | 56 ++---- .../noi-applicant.template.ts | 168 +++++++--------- .../noi-government.template.ts | 56 ++---- .../tur-applicant.template.ts | 158 ++++++--------- .../submitted-to-lfng/applicant.template.ts | 102 ++++------ .../submitted-to-lfng/government.template.ts | 87 +++------ .../emails/submitted-to-lfng/index.ts | 2 - .../emails/under-review-by-alc.template.ts | 60 ++---- .../emails/under-review-by-lfng.template.ts | 64 ++---- .../templates/emails/wrong-lfng.template.ts | 60 ++---- 44 files changed, 611 insertions(+), 1327 deletions(-) delete mode 100644 services/libs/common/src/email-template-service/email-template.service.spec.ts delete mode 100644 services/libs/common/src/email-template-service/email-template.service.ts delete mode 100644 services/templates/emails/cancelled/index.ts delete mode 100644 services/templates/emails/decision-released/index.ts create mode 100644 services/templates/emails/index.ts delete mode 100644 services/templates/emails/partials/index.ts delete mode 100644 services/templates/emails/return-to-lfng/index.ts delete mode 100644 services/templates/emails/submitted-to-alc/index.ts delete mode 100644 services/templates/emails/submitted-to-lfng/index.ts diff --git a/services/apps/alcs/src/alcs/application/application-submission/application-submission.controller.ts b/services/apps/alcs/src/alcs/application/application-submission/application-submission.controller.ts index 0446e4a990..7030acd9e2 100644 --- a/services/apps/alcs/src/alcs/application/application-submission/application-submission.controller.ts +++ b/services/apps/alcs/src/alcs/application/application-submission/application-submission.controller.ts @@ -12,7 +12,7 @@ import { Mapper } from 'automapper-core'; import { InjectMapper } from 'automapper-nestjs'; import * as config from 'config'; import { ServiceValidationException } from '../../../../../../libs/common/src/exceptions/base.exception'; -import { generateINCGApplicationHtml } from '../../../../../../templates/emails/return-to-lfng'; +import { template } from '../../../../../../templates/emails/return-to-lfng/application.template'; import { ANY_AUTH_ROLE } from '../../../common/authorization/roles'; import { RolesGuard } from '../../../common/authorization/roles-guard.service'; import { UserRoles } from '../../../common/authorization/roles.decorator'; @@ -144,7 +144,7 @@ export class ApplicationSubmissionController { //Send Email if (primaryContact && submissionGovernment) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateINCGApplicationHtml, + template, status: SUBMISSION_STATUS.RETURNED_TO_LG, applicationSubmission: submission, government: submissionGovernment, diff --git a/services/apps/alcs/src/alcs/application/application.controller.ts b/services/apps/alcs/src/alcs/application/application.controller.ts index f66ee885ab..b585714c46 100644 --- a/services/apps/alcs/src/alcs/application/application.controller.ts +++ b/services/apps/alcs/src/alcs/application/application.controller.ts @@ -18,7 +18,7 @@ import { } from '@nestjs/common'; import { ApiOAuth2 } from '@nestjs/swagger'; import * as config from 'config'; -import { generateCANCApplicationHtml } from '../../../../../templates/emails/cancelled'; +import { template } from '../../../../../templates/emails/cancelled/application.template'; import { ROLES_ALLOWED_APPLICATIONS } from '../../common/authorization/roles'; import { RolesGuard } from '../../common/authorization/roles-guard.service'; import { UserRoles } from '../../common/authorization/roles.decorator'; @@ -144,7 +144,7 @@ export class ApplicationController { SUBMISSION_STATUS.IN_PROGRESS ) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateCANCApplicationHtml, + template, status: SUBMISSION_STATUS.CANCELLED, applicationSubmission, government: submissionGovernment, diff --git a/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent.controller.ts b/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent.controller.ts index 4a58d4afcc..daae6fd1fa 100644 --- a/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent.controller.ts +++ b/services/apps/alcs/src/alcs/notice-of-intent/notice-of-intent.controller.ts @@ -11,7 +11,7 @@ import { ApiOAuth2 } from '@nestjs/swagger'; import { Mapper } from 'automapper-core'; import { InjectMapper } from 'automapper-nestjs'; import * as config from 'config'; -import { generateCANCNoticeOfIntentHtml } from '../../../../../templates/emails/cancelled'; +import { template } from '../../../../../templates/emails/cancelled/notice-of-intent.template'; import { ROLES_ALLOWED_APPLICATIONS, ROLES_ALLOWED_BOARDS, @@ -111,7 +111,7 @@ export class NoticeOfIntentController { NOI_SUBMISSION_STATUS.IN_PROGRESS ) { await this.statusEmailService.sendNoticeOfIntentStatusEmail({ - generateStatusHtml: generateCANCNoticeOfIntentHtml, + template, status: NOI_SUBMISSION_STATUS.CANCELLED, noticeOfIntentSubmission, government: submissionGovernment, diff --git a/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.ts b/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.ts index 58d59eaf81..7ff8eb4615 100644 --- a/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.ts +++ b/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.ts @@ -12,11 +12,11 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { generateRFFGHtml } from '../../../../../templates/emails/refused-to-forward.template'; -import { generateINCMHtml } from '../../../../../templates/emails/returned-as-incomplete.template'; -import { generateSUBMApplicationHtml } from '../../../../../templates/emails/submitted-to-alc'; -import { generateREVGHtml } from '../../../../../templates/emails/under-review-by-lfng.template'; -import { generateWRNGHtml } from '../../../../../templates/emails/wrong-lfng.template'; +import { template as rffgTemplate } from '../../../../../templates/emails/refused-to-forward.template'; +import { template as incmTemplate } from '../../../../../templates/emails/returned-as-incomplete.template'; +import { template as submApplicationTemplate } from '../../../../../templates/emails/submitted-to-alc/application.template'; +import { template as revgTemplate } from '../../../../../templates/emails/under-review-by-lfng.template'; +import { template as wrngTemplate } from '../../../../../templates/emails/wrong-lfng.template'; import { ApplicationDocumentService } from '../../alcs/application/application-document/application-document.service'; import { ApplicationSubmissionStatusService } from '../../alcs/application/application-submission-status/application-submission-status.service'; import { SUBMISSION_STATUS } from '../../alcs/application/application-submission-status/submission-status.dto'; @@ -193,7 +193,7 @@ export class ApplicationSubmissionReviewController { if (primaryContact) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateREVGHtml, + template: revgTemplate, status: SUBMISSION_STATUS.IN_REVIEW_BY_LG, applicationSubmission, government: userLocalGovernment, @@ -302,7 +302,7 @@ export class ApplicationSubmissionReviewController { if (primaryContact) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateSUBMApplicationHtml, + template: submApplicationTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_ALC, applicationSubmission: submission, government: userLocalGovernment, @@ -320,7 +320,7 @@ export class ApplicationSubmissionReviewController { if (primaryContact) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateRFFGHtml, + template: rffgTemplate, status: SUBMISSION_STATUS.REFUSED_TO_FORWARD_LG, applicationSubmission: submission, government: userLocalGovernment, @@ -412,7 +412,7 @@ export class ApplicationSubmissionReviewController { if (primaryContact) { if (returnDto.reasonForReturn === 'wrongGovernment') { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateWRNGHtml, + template: wrngTemplate, status: SUBMISSION_STATUS.WRONG_GOV, applicationSubmission, government: userLocalGovernment, @@ -424,7 +424,7 @@ export class ApplicationSubmissionReviewController { if (returnDto.reasonForReturn === 'incomplete') { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateINCMHtml, + template: incmTemplate, status: SUBMISSION_STATUS.INCOMPLETE, applicationSubmission, government: userLocalGovernment, diff --git a/services/apps/alcs/src/portal/application-submission/application-submission.controller.ts b/services/apps/alcs/src/portal/application-submission/application-submission.controller.ts index 72cb299ad6..08b1bc3c1d 100644 --- a/services/apps/alcs/src/portal/application-submission/application-submission.controller.ts +++ b/services/apps/alcs/src/portal/application-submission/application-submission.controller.ts @@ -14,16 +14,12 @@ import { BaseServiceException, ServiceValidationException, } from '../../../../../libs/common/src/exceptions/base.exception'; -import { generateCANCApplicationHtml } from '../../../../../templates/emails/cancelled'; -import { - generateSUBGNoReviewGovernmentTemplateEmail, - generateSUBGTurApplicantHtml, -} from '../../../../../templates/emails/submitted-to-alc'; -import { generateSUBGCoveApplicantHtml } from '../../../../../templates/emails/submitted-to-alc/cove-applicant.template'; -import { - generateSUBGApplicantHtml, - generateSUBGGovernmentHtml, -} from '../../../../../templates/emails/submitted-to-lfng'; +import { template as cancApplicationTemplate } from '../../../../../templates/emails/cancelled/application.template'; +import { template as subgNoReviewGovernmentTemplate } from '../../../../../templates/emails/submitted-to-alc/no-review-government.template'; +import { template as subgTurApplicantTemplate } from '../../../../../templates/emails/submitted-to-alc/tur-applicant.template'; +import { template as subgCoveApplicantTemplate } from '../../../../../templates/emails/submitted-to-alc/cove-applicant.template'; +import { template as subgApplicantTemplate } from '../../../../../templates/emails/submitted-to-lfng/applicant.template'; +import { template as subgGovernmentTemplate } from '../../../../../templates/emails/submitted-to-lfng/government.template'; import { SUBMISSION_STATUS } from '../../alcs/application/application-submission-status/submission-status.dto'; import { ApplicationService } from '../../alcs/application/application.service'; import { PARENT_TYPE } from '../../alcs/card/card-subtask/card-subtask.dto'; @@ -224,7 +220,7 @@ export class ApplicationSubmissionController { application.status.statusTypeCode !== SUBMISSION_STATUS.IN_PROGRESS ) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateCANCApplicationHtml, + template: cancApplicationTemplate, status: SUBMISSION_STATUS.CANCELLED, applicationSubmission: application, government: submissionGovernment, @@ -291,7 +287,7 @@ export class ApplicationSubmissionController { if (matchingType.requiresGovernmentReview) { if (primaryContact) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateSUBGApplicantHtml, + template: subgApplicantTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_LG, applicationSubmission: validatedSubmission, government: submissionGovernment, @@ -303,7 +299,7 @@ export class ApplicationSubmissionController { if (submissionGovernment) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateSUBGGovernmentHtml, + template: subgGovernmentTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_LG, applicationSubmission: validatedSubmission, government: submissionGovernment, @@ -326,13 +322,13 @@ export class ApplicationSubmissionController { matchingType.code === APPLICATION_SUBMISSION_TYPES.TURP || matchingType.code === APPLICATION_SUBMISSION_TYPES.COVE ) { - const generateTemplateFunction = + const template = matchingType.code === APPLICATION_SUBMISSION_TYPES.TURP - ? generateSUBGTurApplicantHtml - : generateSUBGCoveApplicantHtml; + ? subgTurApplicantTemplate + : subgCoveApplicantTemplate; await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateTemplateFunction, + template: template, status: SUBMISSION_STATUS.SUBMITTED_TO_ALC, applicationSubmission: validatedSubmission, government: submissionGovernment, @@ -344,7 +340,7 @@ export class ApplicationSubmissionController { if (submissionGovernment) { await this.statusEmailService.sendApplicationStatusEmail({ - generateStatusHtml: generateSUBGNoReviewGovernmentTemplateEmail, + template: subgNoReviewGovernmentTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_ALC, applicationSubmission: validatedSubmission, government: submissionGovernment, diff --git a/services/apps/alcs/src/portal/notice-of-intent-submission-draft/notice-of-intent-submission-draft.service.ts b/services/apps/alcs/src/portal/notice-of-intent-submission-draft/notice-of-intent-submission-draft.service.ts index 1c08aa6ba4..d53bf59f5b 100644 --- a/services/apps/alcs/src/portal/notice-of-intent-submission-draft/notice-of-intent-submission-draft.service.ts +++ b/services/apps/alcs/src/portal/notice-of-intent-submission-draft/notice-of-intent-submission-draft.service.ts @@ -2,7 +2,7 @@ import { BaseServiceException } from '@app/common/exceptions/base.exception'; import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { generateSUBMNoiGovernmentHtml } from '../../../../../templates/emails/submitted-to-alc/noi-government.template'; +import { template } from '../../../../../templates/emails/submitted-to-alc/noi-government.template'; import { PARENT_TYPE } from '../../alcs/card/card-subtask/card-subtask.dto'; import { LocalGovernmentService } from '../../alcs/local-government/local-government.service'; import { NOI_SUBMISSION_STATUS } from '../../alcs/notice-of-intent/notice-of-intent-submission-status/notice-of-intent-status.dto'; @@ -250,7 +250,7 @@ export class NoticeOfIntentSubmissionDraftService { if (submissionGovernment) { await this.statusEmailService.sendNoticeOfIntentStatusEmail({ - generateStatusHtml: generateSUBMNoiGovernmentHtml, + template, status: NOI_SUBMISSION_STATUS.SUBMITTED_TO_ALC, noticeOfIntentSubmission: savedDraft, government: submissionGovernment, diff --git a/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.ts b/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.ts index 74e4b68215..35aad3bd91 100644 --- a/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.ts +++ b/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.ts @@ -10,10 +10,8 @@ import { Req, UseGuards, } from '@nestjs/common'; -import { - generateSUBMNoiApplicantHtml, - generateSUBMNoiGovernmentHtml, -} from '../../../../../templates/emails/submitted-to-alc'; +import { template as submNoiApplicantTemplate } from '../../../../../templates/emails/submitted-to-alc/noi-applicant.template'; +import { template as submNoiGovernmentTemplate } from '../../../../../templates/emails/submitted-to-alc/noi-government.template'; import { PARENT_TYPE } from '../../alcs/card/card-subtask/card-subtask.dto'; import { LocalGovernmentService } from '../../alcs/local-government/local-government.service'; import { NOI_SUBMISSION_STATUS } from '../../alcs/notice-of-intent/notice-of-intent-submission-status/notice-of-intent-status.dto'; @@ -191,7 +189,7 @@ export class NoticeOfIntentSubmissionController { if (primaryContact) { await this.statusEmailService.sendNoticeOfIntentStatusEmail({ - generateStatusHtml: generateSUBMNoiApplicantHtml, + template: submNoiApplicantTemplate, status: NOI_SUBMISSION_STATUS.SUBMITTED_TO_ALC, noticeOfIntentSubmission, government: submissionGovernment, @@ -203,7 +201,7 @@ export class NoticeOfIntentSubmissionController { if (submissionGovernment) { await this.statusEmailService.sendNoticeOfIntentStatusEmail({ - generateStatusHtml: generateSUBMNoiGovernmentHtml, + template: submNoiGovernmentTemplate, status: NOI_SUBMISSION_STATUS.SUBMITTED_TO_ALC, noticeOfIntentSubmission, government: submissionGovernment, diff --git a/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts b/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts index 4b8f7c0bb6..f31aa220fb 100644 --- a/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts +++ b/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts @@ -11,7 +11,7 @@ import { Not, Repository, } from 'typeorm'; -import { generateSRWTemplate } from '../../../../../templates/emails/notifications/srw-notice.template'; +import { template } from '../../../../../templates/emails/notifications/srw-notice.template'; import { SUBMISSION_STATUS } from '../../alcs/application/application-submission-status/submission-status.dto'; import { PARENT_TYPE } from '../../alcs/card/card-subtask/card-subtask.dto'; import { LocalGovernmentService } from '../../alcs/local-government/local-government.service'; @@ -38,6 +38,7 @@ import { NotificationSubmissionUpdateDto, } from './notification-submission.dto'; import { NotificationSubmission } from './notification-submission.entity'; +import { compile } from 'handlebars'; @Injectable() export class NotificationSubmissionService { @@ -462,7 +463,7 @@ export class NotificationSubmissionService { submission.fileNumber, ); - const emailTemplate = generateSRWTemplate({ + const html = compile(template)({ fileNumber: submission.fileNumber, contactName: `${submission.contactFirstName} ${submission.contactLastName}`, status: 'ALC Response Sent', @@ -485,7 +486,7 @@ export class NotificationSubmissionService { } return { - html: emailTemplate.html, + html: html, cc: ccEmails, to: submission.contactEmail!, parentId: notification.uuid, diff --git a/services/apps/alcs/src/providers/email/status-email.service.ts b/services/apps/alcs/src/providers/email/status-email.service.ts index 9f01c965ea..261fece800 100644 --- a/services/apps/alcs/src/providers/email/status-email.service.ts +++ b/services/apps/alcs/src/providers/email/status-email.service.ts @@ -1,6 +1,5 @@ import { CONFIG_TOKEN, IConfig } from '@app/common/config/config.module'; import { Inject, Injectable, Logger, NotFoundException } from '@nestjs/common'; -import { MJMLParseResults } from 'mjml-core'; import { ApplicationDecisionV2Service } from '../../alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service'; import { ApplicationDecision } from '../../alcs/application-decision/application-decision.entity'; import { SUBMISSION_STATUS } from '../../alcs/application/application-submission-status/submission-status.dto'; @@ -20,6 +19,7 @@ import { NoticeOfIntentSubmission } from '../../portal/notice-of-intent-submissi import { NoticeOfIntentSubmissionService } from '../../portal/notice-of-intent-submission/notice-of-intent-submission.service'; import { FALLBACK_APPLICANT_NAME } from '../../utils/owner.constants'; import { EmailService } from './email.service'; +import { compile } from 'handlebars'; export interface StatusUpdateEmail { fileNumber: string; @@ -36,7 +36,7 @@ export type DocumentEmailData = { }; type BaseStatusEmailData = { - generateStatusHtml: MJMLParseResults; + template: string; government: LocalGovernment | null; parentType: PARENT_TYPE; ccGovernment?: boolean; @@ -182,7 +182,7 @@ export class StatusEmailService { const applicantName = data.applicationSubmission.applicant || FALLBACK_APPLICANT_NAME; - const emailTemplate = data.generateStatusHtml({ + const html = compile(data.template)({ fileNumber, applicantName, childType: @@ -198,7 +198,7 @@ export class StatusEmailService { const parentId = await this.applicationService.getUuid(fileNumber); return { - body: emailTemplate.html, + body: html, subject: `Agricultural Land Commission Application ID: ${fileNumber} (${applicantName})`, parentType: data.parentType, parentId, @@ -222,7 +222,7 @@ export class StatusEmailService { const applicantName = data.noticeOfIntentSubmission.applicant || FALLBACK_APPLICANT_NAME; - const emailTemplate = data.generateStatusHtml({ + const html = compile(data.template)({ fileNumber, applicantName, childType: @@ -238,7 +238,7 @@ export class StatusEmailService { const parentId = await this.noticeOfIntentService.getUuid(fileNumber); return { - body: emailTemplate.html, + body: html, subject: `Agricultural Land Commission NOI ID: ${fileNumber} (${applicantName})`, parentType: data.parentType, parentId, diff --git a/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.ts b/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.ts index c18abf7f7e..4e4cfc28e3 100644 --- a/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.ts +++ b/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.ts @@ -3,8 +3,8 @@ import { Logger } from '@nestjs/common'; import * as dayjs from 'dayjs'; import * as timezone from 'dayjs/plugin/timezone'; import * as utc from 'dayjs/plugin/utc'; -import { generateALCDApplicationHtml } from '../../../../../../../templates/emails/decision-released'; -import { generateREVAHtml } from '../../../../../../../templates/emails/under-review-by-alc.template'; +import { template as alcdApplicationTemplate } from '../../../../../../../templates/emails/decision-released/application.template'; +import { template as revaTemplate } from '../../../../../../../templates/emails/under-review-by-alc.template'; import { ApplicationDecisionV2Service } from '../../../../alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service'; import { ApplicationSubmissionStatusService } from '../../../../alcs/application/application-submission-status/application-submission-status.service'; import { SUBMISSION_STATUS } from '../../../../alcs/application/application-submission-status/submission-status.dto'; @@ -107,10 +107,10 @@ export class ApplicationDecisionEmailConsumer extends WorkerHost { applicationSubmission.status.statusTypeCode === submissionStatus.statusTypeCode ) { - const generateStatusHtml = + const template = submissionStatus.statusTypeCode === SUBMISSION_STATUS.ALC_DECISION - ? generateALCDApplicationHtml - : generateREVAHtml; + ? alcdApplicationTemplate + : revaTemplate; const documents = await this.statusEmailService.getApplicationDecisionDocuments( @@ -123,7 +123,7 @@ export class ApplicationDecisionEmailConsumer extends WorkerHost { parentType: PARENT_TYPE.APPLICATION, primaryContact, ccGovernment: true, - generateStatusHtml, + template, status: submissionStatus.statusTypeCode, documents, ccEmails, diff --git a/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.ts b/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.ts index 2a91c78931..685b7757a1 100644 --- a/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.ts +++ b/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.ts @@ -3,8 +3,8 @@ import { Logger } from '@nestjs/common'; import * as dayjs from 'dayjs'; import * as timezone from 'dayjs/plugin/timezone'; import * as utc from 'dayjs/plugin/utc'; -import { generateALCDApplicationHtml } from '../../../../../../../templates/emails/decision-released'; -import { generateREVAHtml } from '../../../../../../../templates/emails/under-review-by-alc.template'; +import { template as alcdApplicationTemplate } from '../../../../../../../templates/emails/decision-released/application.template'; +import { template as revaTemplate } from '../../../../../../../templates/emails/under-review-by-alc.template'; import { ApplicationSubmissionStatusService } from '../../../../alcs/application/application-submission-status/application-submission-status.service'; import { SUBMISSION_STATUS } from '../../../../alcs/application/application-submission-status/submission-status.dto'; import { ApplicationSubmissionToSubmissionStatus } from '../../../../alcs/application/application-submission-status/submission-status.entity'; @@ -89,10 +89,10 @@ export class ApplicationSubmissionStatusEmailConsumer extends WorkerHost { applicationSubmission.status.statusTypeCode === submissionStatus.statusTypeCode ) { - const generateStatusHtml = + const template = submissionStatus.statusTypeCode === SUBMISSION_STATUS.ALC_DECISION - ? generateALCDApplicationHtml - : generateREVAHtml; + ? alcdApplicationTemplate + : revaTemplate; const documents = submissionStatus.statusTypeCode === SUBMISSION_STATUS.ALC_DECISION @@ -105,7 +105,7 @@ export class ApplicationSubmissionStatusEmailConsumer extends WorkerHost { parentType: PARENT_TYPE.APPLICATION, primaryContact, ccGovernment: true, - generateStatusHtml, + template, status: submissionStatus.statusTypeCode, documents, ccEmails: [], diff --git a/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.ts b/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.ts index 7fbfb8262f..4bab122214 100644 --- a/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.ts +++ b/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.ts @@ -3,7 +3,7 @@ import { Logger } from '@nestjs/common'; import * as dayjs from 'dayjs'; import * as timezone from 'dayjs/plugin/timezone'; import * as utc from 'dayjs/plugin/utc'; -import { generateALCDNoticeOfIntentHtml } from '../../../../../../templates/emails/decision-released'; +import { template } from '../../../../../../templates/emails/decision-released/notice-of-intent.template'; import { PARENT_TYPE } from '../../../alcs/card/card-subtask/card-subtask.dto'; import { NoticeOfIntentDecisionV2Service } from '../../../alcs/notice-of-intent-decision/notice-of-intent-decision-v2/notice-of-intent-decision-v2.service'; import { NOI_SUBMISSION_STATUS } from '../../../alcs/notice-of-intent/notice-of-intent-submission-status/notice-of-intent-status.dto'; @@ -55,7 +55,7 @@ export class NoticeOfIntentDecisionEmailsConsumer extends WorkerHost { if (primaryContact) { await this.statusEmailService.sendNoticeOfIntentStatusEmail({ - generateStatusHtml: generateALCDNoticeOfIntentHtml, + template, status: NOI_SUBMISSION_STATUS.ALC_DECISION, noticeOfIntentSubmission: submission, government: submissionGovernment, diff --git a/services/libs/common/src/email-template-service/email-template.service.spec.ts b/services/libs/common/src/email-template-service/email-template.service.spec.ts deleted file mode 100644 index 7f5ac06ba2..0000000000 --- a/services/libs/common/src/email-template-service/email-template.service.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { EmailTemplateService } from './email-template.service'; - -describe('EmailTemplateService', () => { - let service: EmailTemplateService; - - beforeEach(() => { - service = new EmailTemplateService(); - }); - - describe('generateEmailBase', () => { - it('should generate an email base from a template and data', () => { - const template = `Hello {{name}}`; - const data = { name: 'John Smith' }; - const options = {}; - - const result = service.generateEmailBase(template, data, options); - - expect(result.html).toBeDefined(); - expect(result.html).toContain('Hello John Smith'); - }); - }); -}); diff --git a/services/libs/common/src/email-template-service/email-template.service.ts b/services/libs/common/src/email-template-service/email-template.service.ts deleted file mode 100644 index 01f9b0f062..0000000000 --- a/services/libs/common/src/email-template-service/email-template.service.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { compile } from 'handlebars'; -import * as mjml2html from 'mjml'; -import { MJMLParseResults, MJMLParsingOptions } from 'mjml-core'; - -@Injectable() -export class EmailTemplateService { - generateEmailBase( - templateMjml: string, - data?: any, - options?: MJMLParsingOptions, - ): MJMLParseResults { - // prepare template - const compiledTemplate = compile(templateMjml); - - // insert data - const mjml = compiledTemplate(data); - - // render mjml -> html - const htmlOutput = mjml2html(mjml, options); - - return htmlOutput; - } -} diff --git a/services/templates/emails/cancelled/application.template.ts b/services/templates/emails/cancelled/application.template.ts index ed0b973d56..d8edeffeed 100644 --- a/services/templates/emails/cancelled/application.template.ts +++ b/services/templates/emails/cancelled/application.template.ts @@ -1,44 +1,12 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the above noted {{ childType }} application has been cancelled and will not be considered further. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateCANCApplicationHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; + +export const template = build( + `

+ This email is to advise that the above noted {{ childType }} application has been cancelled and will not be considered further. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/cancelled/index.ts b/services/templates/emails/cancelled/index.ts deleted file mode 100644 index cf7fa6130d..0000000000 --- a/services/templates/emails/cancelled/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './application.template'; -export * from './notice-of-intent.template'; diff --git a/services/templates/emails/cancelled/notice-of-intent.template.ts b/services/templates/emails/cancelled/notice-of-intent.template.ts index e5923d0e48..f4b16692fa 100644 --- a/services/templates/emails/cancelled/notice-of-intent.template.ts +++ b/services/templates/emails/cancelled/notice-of-intent.template.ts @@ -1,44 +1,12 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the above noted {{ childType }} Notice of Intent has been cancelled and will not be considered further. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateCANCNoticeOfIntentHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; + +export const template = build( + `

+ This email is to advise that the above noted {{ childType }} Notice of Intent has been cancelled and will not be considered further. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/decision-released/application.template.ts b/services/templates/emails/decision-released/application.template.ts index 2df5976c14..cd0ca456e2 100644 --- a/services/templates/emails/decision-released/application.template.ts +++ b/services/templates/emails/decision-released/application.template.ts @@ -1,67 +1,28 @@ -import { MJMLParseResults } from 'mjml-core'; -import { - DocumentEmailData, - StatusUpdateEmail, -} from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; -type DecisionReleasedStatusEmail = StatusUpdateEmail & { - documents: DocumentEmailData[]; -}; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the Reasons for Decision for the above noted application has been released. - - - You can access the decision document by clicking the link(s) below: - - -
    - {{#each documents}} -
  • {{name}}
  • - {{/each}} -
-
- - The decision can also be accessed via the ALC Portal and Public Search tool. - - - Further correspondence with respect to this application should be directed to the ALC Land Use Planner for your region, found on the ALC website Contact Us page. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise them of this, and any future, correspondence. - - ${notificationOnly} -
-
- - ${portalButton} - - ${footer()} -
-
-`; - -export const generateALCDApplicationHtml = ( - data: DecisionReleasedStatusEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ This email is to advise that the Reasons for Decision for the above noted application has been released. +

+

+ You can access the decision document by clicking the link(s) below: +

+

+

    + {{#each documents}} +
  • {{name}}
  • + {{/each}} +
+

+

+ The decision can also be accessed via the ALC Portal and Public Search tool. +

+

+ Further correspondence with respect to this application should be directed to the ALC Land Use Planner for your region, found on the ALC website Contact Us page. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise them of this, and any future, correspondence. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/decision-released/index.ts b/services/templates/emails/decision-released/index.ts deleted file mode 100644 index cf7fa6130d..0000000000 --- a/services/templates/emails/decision-released/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './application.template'; -export * from './notice-of-intent.template'; diff --git a/services/templates/emails/decision-released/notice-of-intent.template.ts b/services/templates/emails/decision-released/notice-of-intent.template.ts index 2e4112ab62..1579fe3106 100644 --- a/services/templates/emails/decision-released/notice-of-intent.template.ts +++ b/services/templates/emails/decision-released/notice-of-intent.template.ts @@ -1,67 +1,28 @@ -import { MJMLParseResults } from 'mjml-core'; -import { - DocumentEmailData, - StatusUpdateEmail, -} from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { footer, header, notificationOnly, portalButton } from '../partials'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; -type DecisionReleasedStatusEmail = StatusUpdateEmail & { - documents: DocumentEmailData[]; -}; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the Reasons for Decision for the above noted Notice of Intent (NOI) has been released. - - - You can access the decision document by clicking the link(s) below: - - -
    - {{#each documents}} -
  • {{name}}
  • - {{/each}} -
-
- - The decision can also be accessed via the ALC Portal and Public Search tool. - - - Further correspondence with respect to this NOI should be directed to ALC.Soil@gov.bc.ca. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise them of this, and any future, correspondence. - - ${notificationOnly} -
-
- - ${portalButton} - - ${footer()} -
-
-`; - -export const generateALCDNoticeOfIntentHtml = ( - data: DecisionReleasedStatusEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ This email is to advise that the Reasons for Decision for the above noted Notice of Intent (NOI) has been released. +

+

+ You can access the decision document by clicking the link(s) below: +

+

+

    + {{#each documents}} +
  • {{name}}
  • + {{/each}} +
+

+

+ The decision can also be accessed via the ALC Portal and Public Search tool. +

+

+ Further correspondence with respect to this NOI should be directed to ALC.Soil@gov.bc.ca. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise them of this, and any future, correspondence. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/index.ts b/services/templates/emails/index.ts new file mode 100644 index 0000000000..b78297307e --- /dev/null +++ b/services/templates/emails/index.ts @@ -0,0 +1,13 @@ +import { header } from './partials/header.template'; +import { portalButton } from './partials/portal-button.template'; +import { footer } from './partials/footer.template'; + +export const build = ( + content: string, + includeButton: boolean = true, +): string => ` +${header} +${content} +${includeButton ? portalButton : ''} +${footer} +`; diff --git a/services/templates/emails/notifications/srw-notice.template.ts b/services/templates/emails/notifications/srw-notice.template.ts index 28a7c993d4..a7ab0f51ac 100644 --- a/services/templates/emails/notifications/srw-notice.template.ts +++ b/services/templates/emails/notifications/srw-notice.template.ts @@ -1,88 +1,29 @@ -import { MJMLParseResults } from 'mjml-core'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { footer } from '../partials'; -import * as config from 'config'; +import { build } from '..'; -type SrwNoticeTemplateData = { - contactName: string; - status: string; - dateSubmitted: string; - fileNumber: string; - submittersFileNumber: string; - fileName: string; -}; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - - - - Notification ID #SRW{{fileNumber}} - Primary Contact: {{contactName}} - Status: {{status}} - {{dateSubmitted}} - Submitter’s File Number: {{submittersFileNumber}} - - - - - - - - - - - The ALC's attached PDF response is proof that the notification of statutory right of way has been provided for a s. 218 Statutory Right of Way of the Land Title Act as required by s.18.1(2) of the Agricultural Land Commission Act. - - - The ALC's attached PDF response must be appended as an additional document to the LTSA SRW application package. - - - Disclaimer for Transferee(s): - - - This letter is not an approval to use, construct, or remove soil or place fill (including gravel) within the SRW, nor does it compel the ALC to approve construction in the SRW. An application or notice of intent must be submitted to the ALC before starting any construction, fill placement, or soil removal within the SRW. Please consult the ALC for direction. - - - Please refer to ALC Notification ID SRW{{fileNumber}} in all future correspondence with this office. If you are acting on behalf of the transferee, it is your responsibility to advise your client(s) of this, and any future, correspondence. - - - Further correspondence with respect to this notification should be directed to ALC.LUPRT@gov.bc.ca. - - - PROVINCIAL AGRICULTURAL LAND COMMISSION - - - Attachment: {{fileName}} - - - - - ${footer()} - - -`; - -export const generateSRWTemplate = ( - data: SrwNoticeTemplateData, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ The ALC's attached PDF response is proof that the notification of statutory right of way has been provided for a s. 218 Statutory Right of Way of the Land Title Act as required by s.18.1(2) of the Agricultural Land Commission Act. +

+

+ The ALC's attached PDF response must be appended as an additional document to the LTSA SRW application package. +

+

+ Disclaimer for Transferee(s): +

+

+ This letter is not an approval to use, construct, or remove soil or place fill (including gravel) within the SRW, nor does it compel the ALC to approve construction in the SRW. An application or notice of intent must be submitted to the ALC before starting any construction, fill placement, or soil removal within the SRW. Please consult the ALC for direction. +

+

+ Please refer to ALC Notification ID SRW{{ fileNumber }} in all future correspondence with this office. If you are acting on behalf of the transferee, it is your responsibility to advise your client(s) of this, and any future, correspondence. +

+

+ Further correspondence with respect to this notification should be directed to ALC.LUPRT@gov.bc.ca. +

+

+ PROVINCIAL AGRICULTURAL LAND COMMISSION +

+

+ Attachment: {{fileName}} +

`, + false, +); diff --git a/services/templates/emails/partials/footer.template.ts b/services/templates/emails/partials/footer.template.ts index 0f045072d0..5a2b745ffb 100644 --- a/services/templates/emails/partials/footer.template.ts +++ b/services/templates/emails/partials/footer.template.ts @@ -1,15 +1,9 @@ import { v4 } from 'uuid'; -export const footer = () => ` - - - Provincial Agricultural Land Commission (gov.bc.ca) - - - Contact: 604-660-7000 - - - - ${v4()} - - `; +export const footer = ` + Provincial Agricultural Land Commission (gov.bc.ca) + Contact: 604-660-7000 + ${v4()} + + +`; diff --git a/services/templates/emails/partials/header.template.ts b/services/templates/emails/partials/header.template.ts index 21b652a49d..74849d9d10 100644 --- a/services/templates/emails/partials/header.template.ts +++ b/services/templates/emails/partials/header.template.ts @@ -1,21 +1,18 @@ import * as config from 'config'; export const header = ` - - - {{ parentTypeLabel }} ID #{{fileNumber}} - Name: {{applicantName}} - Status: {{status}} - - - - - - `; + + + + + + Document + + + {{ parentTypeLabel }} ID #{{ fileNumber }} + Name: {{ applicantName }} + Status: {{ status }} + +`; diff --git a/services/templates/emails/partials/index.ts b/services/templates/emails/partials/index.ts deleted file mode 100644 index d7b8faeabe..0000000000 --- a/services/templates/emails/partials/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './footer.template'; -export * from './header.template'; -export * from './notification-only.template'; -export * from './portal-button.template'; diff --git a/services/templates/emails/partials/notification-only.template.ts b/services/templates/emails/partials/notification-only.template.ts index e8c09a1140..5d6418d85a 100644 --- a/services/templates/emails/partials/notification-only.template.ts +++ b/services/templates/emails/partials/notification-only.template.ts @@ -1,5 +1,5 @@ export const notificationOnly = ` - +

This is an ALC Portal notification only. Please do not reply to this email. - - `; +

+`; diff --git a/services/templates/emails/partials/portal-button.template.ts b/services/templates/emails/partials/portal-button.template.ts index 1ec767e6da..8c8f358a61 100644 --- a/services/templates/emails/partials/portal-button.template.ts +++ b/services/templates/emails/partials/portal-button.template.ts @@ -1,18 +1,5 @@ import * as config from 'config'; export const portalButton = ` - - - - GO TO ALC PORTAL - - - - `; + GO TO ALC PORTAL +`; diff --git a/services/templates/emails/refused-to-forward.template.ts b/services/templates/emails/refused-to-forward.template.ts index bc6f348fab..efb1d68bba 100644 --- a/services/templates/emails/refused-to-forward.template.ts +++ b/services/templates/emails/refused-to-forward.template.ts @@ -1,48 +1,18 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from './partials'; +import { build } from '.'; +import { notificationOnly } from './partials/notification-only.template'; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the above noted {{ childType }} application has been reviewed by the {{ governmentName }} which has determined not to forward your application to the Agricultural Land Commission for further review. - - - If you have any questions about this outcome, please contact {{ governmentName }}. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - - Login to the ALC Portal for further information on your application. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateRFFGHtml = (data: StatusUpdateEmail): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + ` + This email is to advise that the above noted {{ childType }} application has been reviewed by the {{ governmentName }} which has determined not to forward your application to the Agricultural Land Commission for further review. + + + If you have any questions about this outcome, please contact {{ governmentName }}. + + + If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. + + + Login to the ALC Portal for further information on your application. + + ${notificationOnly}`, +); diff --git a/services/templates/emails/return-to-lfng/application.template.ts b/services/templates/emails/return-to-lfng/application.template.ts index 61b783b0f3..a2ac4e90b6 100644 --- a/services/templates/emails/return-to-lfng/application.template.ts +++ b/services/templates/emails/return-to-lfng/application.template.ts @@ -1,44 +1,12 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the {{ governmentName }}'s review of the above noted {{ childType }} application requires further attention. The ALC has returned the application to the {{ governmentName }} for their action. - - - Please login to the ALC Portal to view the ALC's comments for the {{ governmentName }}. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateINCGApplicationHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; + +export const template = build( + `

+ This email is to advise that the {{ governmentName }}'s review of the above noted {{ childType }} application requires further attention. The ALC has returned the application to the {{ governmentName }} for their action. +

+

+ Please login to the ALC Portal to view the ALC's comments for the {{ governmentName }}. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/return-to-lfng/index.ts b/services/templates/emails/return-to-lfng/index.ts deleted file mode 100644 index ca6d3dd119..0000000000 --- a/services/templates/emails/return-to-lfng/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './application.template'; diff --git a/services/templates/emails/returned-as-incomplete.template.ts b/services/templates/emails/returned-as-incomplete.template.ts index ccb5239507..90c46928a0 100644 --- a/services/templates/emails/returned-as-incomplete.template.ts +++ b/services/templates/emails/returned-as-incomplete.template.ts @@ -1,48 +1,18 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from './partials'; +import { build } from '.'; +import { notificationOnly } from './partials/notification-only.template'; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the above noted {{ childType }} application is considered to be incomplete by the {{ governmentName }} and consequently it has been returned to the applicant. - - - Please login to the ALC Portal to view the comments left by the {{ governmentName }}. Please review, edit and re-submit the application. - - - NOTE: Re-submitted applications do not require an additional application fee. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateINCMHtml = (data: StatusUpdateEmail): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ This email is to advise that the above noted {{ childType }} application is considered to be incomplete by the {{ governmentName }} and consequently it has been returned to the applicant. +

+

+ Please login to the ALC Portal to view the comments left by the {{ governmentName }}. Please review, edit and re-submit the application. +

+

+ NOTE: Re-submitted applications do not require an additional application fee. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/submitted-to-alc/application.template.ts b/services/templates/emails/submitted-to-alc/application.template.ts index d84003778d..b222335710 100644 --- a/services/templates/emails/submitted-to-alc/application.template.ts +++ b/services/templates/emails/submitted-to-alc/application.template.ts @@ -1,109 +1,77 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; -import { appFees } from '../submitted-to-lfng'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; +import { appFees } from '../submitted-to-lfng/applicant.template'; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been reviewed by the {{ governmentName }} and submitted to the Agricultural Land Commission for further review. - - - APPLICATION FEES - Payable to the Minister of Finance c/o the ALC - - - - Application Type - ALC Portion of Fee +export const template = build( + `

+ Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been reviewed by the {{ governmentName }} and submitted to the Agricultural Land Commission for further review. +

+

+ APPLICATION FEES - Payable to the Minister of Finance c/o the ALC +

+ + + + + + ${appFees + .map((a) => { + return ` + + + - ${appFees - .map((a) => { - return ` - - - - - `; - }) - .join('')} - - - This fee can be paid: -
    -
  1. Cheque: Made payable to the Minister of Finance c/o the ALC
  2. -
  3. Credit card: Over the phone or in-person
  4. -
-
- - Please include your assigned Application ID with your payment. - - - Mailing address: -
- Agricultural Land Commission -
- 201-4940 Canada Way -
- Burnaby, BC, Canada -
- V5G 4K6 -
-
- - Paying via telephone: -
- Tel: 604-660-7000 -
-
- - If you are making a long-distance call to a provincial government agency, you can place your call through Enquiry BC free of charge: -
- In Victoria call: 250-387-6121 -
- Elsewhere in BC call: 1-800-663-7867 -
-
- - The length of processing time for each application varies depending on the type of application, statutory requirements within the Agricultural Land Commission Act, information provided, necessity for site visit or applicant meetings, etc. - - - Please be advised that the Status of the application in the ALC Portal will update and a notification email will be sent out as the application moves through each stage of the application review process. Should the ALC Land Use Planner require any additional information or clarification regarding the application, they will contact you. Further information about the application process can be obtained from the ALC website. - - - If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. - - - Please log into the ALC Portal for further updates on the application as it progresses. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateSUBMApplicationHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; + `; + }) + .join('')} +
Application TypeALC Portion of Fee
${a.type}$${a.fee}
${a.type}$${a.fee}
+

+ This fee can be paid: +

    +
  1. Cheque: Made payable to the Minister of Finance c/o the ALC
  2. +
  3. Credit card: Over the phone or in-person
  4. +
+

+

+ Please include your assigned Application ID with your payment. +

+

+ Mailing address: +
+ Agricultural Land Commission +
+ 201-4940 Canada Way +
+ Burnaby, BC, Canada +
+ V5G 4K6 +
+

+

+ Paying via telephone: +
+ Tel: 604-660-7000 +
+

+

+ If you are making a long-distance call to a provincial government agency, you can place your call through Enquiry BC free of charge: +
+ In Victoria call: 250-387-6121 +
+ Elsewhere in BC call: 1-800-663-7867 +
+

+

+ The length of processing time for each application varies depending on the type of application, statutory requirements within the Agricultural Land Commission Act, information provided, necessity for site visit or applicant meetings, etc. +

+

+ Please be advised that the Status of the application in the ALC Portal will update and a notification email will be sent out as the application moves through each stage of the application review process. Should the ALC Land Use Planner require any additional information or clarification regarding the application, they will contact you. Further information about the application process can be obtained from the ALC website. +

+

+ If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. +

+

+ Please log into the ALC Portal for further updates on the application as it progresses. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/submitted-to-alc/cove-applicant.template.ts b/services/templates/emails/submitted-to-alc/cove-applicant.template.ts index 506b1cb247..c85c2b8fce 100644 --- a/services/templates/emails/submitted-to-alc/cove-applicant.template.ts +++ b/services/templates/emails/submitted-to-alc/cove-applicant.template.ts @@ -1,53 +1,21 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to acknowledge that the Agricultural Land Commission (ALC) is in receipt of the above noted {{ childType }} application. Please refer to the ALC Application ID in all future correspondence with this office. A copy of this application has been forwarded to the {{ governmentName }} for information purposes. - - - There is no application fee associated with registering a Restrictive Covenant. - - - Please be advised that the status of the application in the ALC Portal will update and a notification email will be sent out as the application moves through each stage of the application review process. Should the ALC Land Use Planner require any additional information or clarification regarding the application, they will contact you. Further information about the application process can be obtained from the ALC website. - - - If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. - - - Please log into the ALC Portal for further updates on the application as it progresses. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateSUBGCoveApplicantHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ This email is to acknowledge that the Agricultural Land Commission (ALC) is in receipt of the above noted {{ childType }} application. Please refer to the ALC Application ID in all future correspondence with this office. A copy of this application has been forwarded to the {{ governmentName }} for information purposes. +

+

+ There is no application fee associated with registering a Restrictive Covenant. +

+

+ Please be advised that the status of the application in the ALC Portal will update and a notification email will be sent out as the application moves through each stage of the application review process. Should the ALC Land Use Planner require any additional information or clarification regarding the application, they will contact you. Further information about the application process can be obtained from the ALC website. +

+

+ If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. +

+

+ Please log into the ALC Portal for further updates on the application as it progresses. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/submitted-to-alc/index.ts b/services/templates/emails/submitted-to-alc/index.ts deleted file mode 100644 index b3862e78c7..0000000000 --- a/services/templates/emails/submitted-to-alc/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './application.template'; -export * from './noi-applicant.template'; -export * from './noi-government.template'; -export * from './tur-applicant.template'; -export * from './no-review-government.template'; diff --git a/services/templates/emails/submitted-to-alc/no-review-government.template.ts b/services/templates/emails/submitted-to-alc/no-review-government.template.ts index fd74535ec9..f763e95839 100644 --- a/services/templates/emails/submitted-to-alc/no-review-government.template.ts +++ b/services/templates/emails/submitted-to-alc/no-review-government.template.ts @@ -1,44 +1,12 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the Agricultural Land Commission. A read-only copy of the application has been submitted to the {{ governmentName }} for informational purposes. Should the {{ governmentName }} wish to comment on the application, please submit comments directly to the ALC. - - - Please log into the ALC Portal to view the application. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateSUBGNoReviewGovernmentTemplateEmail = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; + +export const template = build( + `

+ Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the Agricultural Land Commission. A read-only copy of the application has been submitted to the {{ governmentName }} for informational purposes. Should the {{ governmentName }} wish to comment on the application, please submit comments directly to the ALC. +

+

+ Please log into the ALC Portal to view the application. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/submitted-to-alc/noi-applicant.template.ts b/services/templates/emails/submitted-to-alc/noi-applicant.template.ts index 0601101c0a..e7dd98507a 100644 --- a/services/templates/emails/submitted-to-alc/noi-applicant.template.ts +++ b/services/templates/emails/submitted-to-alc/noi-applicant.template.ts @@ -1,7 +1,5 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; const noiFees = [ { type: 'Removal of Soil', fee: 150 }, @@ -9,100 +7,70 @@ const noiFees = [ { type: 'Placement of Fill/Removal of Soil', fee: 150 }, ]; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to acknowledge that the Agricultural Land Commission (ALC) is in receipt of the above noted {{ childType }} Notice of Intent (NOI). Please refer to the ALC NOI ID in all future correspondence with this office. A copy of this NOI has been forwarded to the {{ governmentName }} for information purposes. - - - NOTICE OF INTENT FEES - Payable to the Minister of Finance c/o the ALC - - - - NOI Type - ALC Portion of Fee +export const template = build( + `

+ This email is to acknowledge that the Agricultural Land Commission (ALC) is in receipt of the above noted {{ childType }} Notice of Intent (NOI). Please refer to the ALC NOI ID in all future correspondence with this office. A copy of this NOI has been forwarded to the {{ governmentName }} for information purposes. +

+

+ NOTICE OF INTENT FEES - Payable to the Minister of Finance c/o the ALC +

+ + + + + + ${noiFees + .map((a) => { + return ` + + + - ${noiFees - .map((a) => { - return ` - - - - - `; - }) - .join('')} - - - This fee can be paid: -
    -
  1. Cheque: Made payable to the Minister of Finance c/o the ALC
  2. -
  3. Credit card: Over the phone or in-person
  4. -
-
- - Please include your assigned NOI ID with your payment. - - - Mailing address: -
- Agricultural Land Commission -
- 201-4940 Canada Way -
- Burnaby, BC, Canada -
- V5G 4K6 -
-
- - Paying via telephone: -
- Tel: 604-660-7000 -
-
- - If you are making a long-distance call to a provincial government agency, you can place your call through Enquiry BC free of charge: -
- In Victoria call: 250-387-6121 -
- Elsewhere in BC call: 1-800-663-7867 -
-
- - If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. - - - Please log into the ALC Portal for further updates on the NOI as it progresses. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateSUBMNoiApplicantHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; + `; + }) + .join('')} +
NOI TypeALC Portion of Fee
${a.type}$${a.fee}
${a.type}$${a.fee}
+

+ This fee can be paid: +

    +
  1. Cheque: Made payable to the Minister of Finance c/o the ALC
  2. +
  3. Credit card: Over the phone or in-person
  4. +
+

+

+ Please include your assigned NOI ID with your payment. +

+

+ Mailing address: +
+ Agricultural Land Commission +
+ 201-4940 Canada Way +
+ Burnaby, BC, Canada +
+ V5G 4K6 +
+

+

+ Paying via telephone: +
+ Tel: 604-660-7000 +
+

+

+ If you are making a long-distance call to a provincial government agency, you can place your call through Enquiry BC free of charge: +
+ In Victoria call: 250-387-6121 +
+ Elsewhere in BC call: 1-800-663-7867 +
+

+

+ If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. +

+

+ Please log into the ALC Portal for further updates on the NOI as it progresses. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/submitted-to-alc/noi-government.template.ts b/services/templates/emails/submitted-to-alc/noi-government.template.ts index 2f90db9f81..331820eec0 100644 --- a/services/templates/emails/submitted-to-alc/noi-government.template.ts +++ b/services/templates/emails/submitted-to-alc/noi-government.template.ts @@ -1,44 +1,12 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - Agricultural Land Commission {{ childType }} NOI ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the Agricultural Land Commission. A read-only copy of the Notice of Intent (NOI) has been submitted to the {{ governmentName }} for informational purposes. Should the {{ governmentName}} wish to comment on the NOI, please submit comments directly to the ALC. - - - Please log into the ALC Portal to view the NOI. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateSUBMNoiGovernmentHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; + +export const template = build( + `

+ Agricultural Land Commission {{ childType }} NOI ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the Agricultural Land Commission. A read-only copy of the Notice of Intent (NOI) has been submitted to the {{ governmentName }} for informational purposes. Should the {{ governmentName}} wish to comment on the NOI, please submit comments directly to the ALC. +

+

+ Please log into the ALC Portal to view the NOI. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/submitted-to-alc/tur-applicant.template.ts b/services/templates/emails/submitted-to-alc/tur-applicant.template.ts index 3fb5a21e0b..99c34b7bd3 100644 --- a/services/templates/emails/submitted-to-alc/tur-applicant.template.ts +++ b/services/templates/emails/submitted-to-alc/tur-applicant.template.ts @@ -1,96 +1,64 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to acknowledge that the Agricultural Land Commission (ALC) is in receipt of the above noted {{ childType }} application. Please refer to the ALC Application ID in all future correspondence with this office. A copy of this application has been forwarded to the {{ governmentName }} for information purposes. - - - APPLICATION FEES - Payable to the Minister of Finance c/o the ALC - - - - Application Type - Application Fee - - - Transportation, Utility, and Recreational Trail Uses - $1500 - - - - This fee can be paid: -
    -
  1. Cheque: Made payable to the Minister of Finance c/o the ALC
  2. -
  3. Credit card: Over the phone or in-person
  4. -
-
- - Please include your assigned Application ID with your payment. - - - Mailing address: -
- Agricultural Land Commission -
- 201-4940 Canada Way -
- Burnaby, BC, Canada -
- V5G 4K6 -
-
- - Paying via telephone: -
- Tel: 604-660-7000 -
-
- - If you are making a long-distance call to a provincial government agency, you can place your call through Enquiry BC free of charge: -
- In Victoria call: 250-387-6121 -
- Elsewhere in BC call: 1-800-663-7867 -
-
- - If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. - - - Please log into the ALC Portal for further updates on the application as it progresses. - - ${notificationOnly} -
-
- - ${portalButton} - - ${footer()} -
-
-`; - -export const generateSUBGTurApplicantHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ This email is to acknowledge that the Agricultural Land Commission (ALC) is in receipt of the above noted {{ childType }} application. Please refer to the ALC Application ID in all future correspondence with this office. A copy of this application has been forwarded to the {{ governmentName }} for information purposes. +

+

+ APPLICATION FEES - Payable to the Minister of Finance c/o the ALC +

+ + + + + + + + + +
Application TypeApplication Fee
Transportation, Utility, and Recreational Trail Uses$1500
+

+ This fee can be paid: +

    +
  1. Cheque: Made payable to the Minister of Finance c/o the ALC
  2. +
  3. Credit card: Over the phone or in-person
  4. +
+

+

+ Please include your assigned Application ID with your payment. +

+

+ Mailing address: +
+ Agricultural Land Commission +
+ 201-4940 Canada Way +
+ Burnaby, BC, Canada +
+ V5G 4K6 +
+

+

+ Paying via telephone: +
+ Tel: 604-660-7000 +
+

+

+ If you are making a long-distance call to a provincial government agency, you can place your call through Enquiry BC free of charge: +
+ In Victoria call: 250-387-6121 +
+ Elsewhere in BC call: 1-800-663-7867 +
+

+

+ If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. +

+

+ Please log into the ALC Portal for further updates on the application as it progresses. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/submitted-to-lfng/applicant.template.ts b/services/templates/emails/submitted-to-lfng/applicant.template.ts index b31127e8fa..c5dcea267f 100644 --- a/services/templates/emails/submitted-to-lfng/applicant.template.ts +++ b/services/templates/emails/submitted-to-lfng/applicant.template.ts @@ -1,7 +1,5 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; export const appFees = [ { type: 'Exclusion', fee: 750 }, @@ -12,67 +10,35 @@ export const appFees = [ { type: 'Inclusion', fee: 0 }, ]; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to acknowledge that you have submitted the above noted {{ childType }} application to the {{ governmentName }}. - - - - Application Type - {{ governmentName }} Portion of Fee - - ${appFees - .map((a) => { - return ` - - ${a.type} - $${a.fee} - - `; - }) - .join('')} - - - Contact the {{ governmentName }} for its payment options. Please include your assigned Application ID with your payment. - - - NOTE: There is no additional fee for re-submission if the {{ governmentName }} returns your application. - - - If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. - - - Please log into the ALC Portal for further updates on the application as it progresses. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateSUBGApplicantHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build(` +

This email is to acknowledge that you have submitted the above noted {{ childType }} application to the {{ governmentName }}. + + + + + + ${appFees + .map((a) => { + return ` + + + + + `; + }) + .join('')} +
Application Type{{ governmentName }} Portion of Fee
${a.type}$${a.fee}
+

+ Contact the {{ governmentName }} for its payment options. Please include your assigned Application ID with your payment. +

+

+ NOTE: There is no additional fee for re-submission if the {{ governmentName }} returns your application. +

+

+ If you are an agent acting on behalf of the applicant(s) / landowner(s), it is your responsibility to advise them of this, and any future, correspondence. +

+

+ Please log into the ALC Portal for further updates on the application as it progresses. +

+${notificationOnly} +`); diff --git a/services/templates/emails/submitted-to-lfng/government.template.ts b/services/templates/emails/submitted-to-lfng/government.template.ts index e355c79ba5..5eb5052a97 100644 --- a/services/templates/emails/submitted-to-lfng/government.template.ts +++ b/services/templates/emails/submitted-to-lfng/government.template.ts @@ -1,61 +1,30 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from '../partials'; +import { build } from '..'; +import { notificationOnly } from '../partials/notification-only.template'; import { appFees } from './applicant.template'; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the {{ governmentName }}. The Applicant has been instructed to contact the {{ governmentName }} for payment instructions regarding the applicable application fee. - - - - Application Type - {{ governmentName }} Portion of Fee - - ${appFees - .map((a) => { - return ` - - ${a.type} - $${a.fee} - - `; - }) - .join('')} - - - Please log into the ALC Portal to view the application. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateSUBGGovernmentHtml = ( - data: StatusUpdateEmail, -): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the {{ governmentName }}. The Applicant has been instructed to contact the {{ governmentName }} for payment instructions regarding the applicable application fee. +

+ + + + + + ${appFees + .map((a) => { + return ` + + + + + `; + }) + .join('')} +
Application Type{{ governmentName }} Portion of Fee
${a.type}$${a.fee}
+

+ Please log into the ALC Portal to view the application. +

+ ${notificationOnly} +`, +); diff --git a/services/templates/emails/submitted-to-lfng/index.ts b/services/templates/emails/submitted-to-lfng/index.ts deleted file mode 100644 index f15e9f56ce..0000000000 --- a/services/templates/emails/submitted-to-lfng/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './applicant.template'; -export * from './government.template'; diff --git a/services/templates/emails/under-review-by-alc.template.ts b/services/templates/emails/under-review-by-alc.template.ts index 9b015d0c75..e7971f417b 100644 --- a/services/templates/emails/under-review-by-alc.template.ts +++ b/services/templates/emails/under-review-by-alc.template.ts @@ -1,45 +1,15 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from './partials'; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - Your application is now under review by the ALC Commissioners. You may be contacted during this review period if additional information or clarification is required. No further action is required from you at this time. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - - Login to the ALC Portal for further updates on your application as it progresses through the application process. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateREVAHtml = (data: StatusUpdateEmail): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +import { build } from '.'; +import { notificationOnly } from './partials/notification-only.template'; + +export const template = build( + `

+ Your application is now under review by the ALC Commissioners. You may be contacted during this review period if additional information or clarification is required. No further action is required from you at this time. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. +

+

+ Login to the ALC Portal for further updates on your application as it progresses through the application process. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/under-review-by-lfng.template.ts b/services/templates/emails/under-review-by-lfng.template.ts index c55b195685..55ca7836ab 100644 --- a/services/templates/emails/under-review-by-lfng.template.ts +++ b/services/templates/emails/under-review-by-lfng.template.ts @@ -1,48 +1,18 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from './partials'; +import { build } from '.'; +import { notificationOnly } from './partials/notification-only.template'; -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the above noted {{ childType }} application has been received by the {{ governmentName }} for review. - - - If you have not already done so, please contact the {{ governmentName }} to determine the preferred form of payment as the application may not be processed until payment is received. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - - Login to the ALC Portal for further updates on your application as it progresses through the application process. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateREVGHtml = (data: StatusUpdateEmail): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +export const template = build( + `

+ This email is to advise that the above noted {{ childType }} application has been received by the {{ governmentName }} for review. +

+

+ If you have not already done so, please contact the {{ governmentName }} to determine the preferred form of payment as the application may not be processed until payment is received. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. +

+

+ Login to the ALC Portal for further updates on your application as it progresses through the application process. +

+ ${notificationOnly}`, +); diff --git a/services/templates/emails/wrong-lfng.template.ts b/services/templates/emails/wrong-lfng.template.ts index 6ddd3d5484..769d317b52 100644 --- a/services/templates/emails/wrong-lfng.template.ts +++ b/services/templates/emails/wrong-lfng.template.ts @@ -1,45 +1,15 @@ -import { MJMLParseResults } from 'mjml-core'; -import { StatusUpdateEmail } from '../../apps/alcs/src/providers/email/status-email.service'; -import { EmailTemplateService } from '../../libs/common/src/email-template-service/email-template.service'; -import { header, footer, notificationOnly, portalButton } from './partials'; - -const template = ` - - - .line-height div { - line-height: 24px !important; - } - - .align-left { - float: left !important; - } - - - - ${header} - - - - - This email is to advise that the above noted {{ childType }} application does not fall within the jurisdiction of the {{ governmentName }} and consequently it has been returned to the applicant. - - - Please login to the ALC Portal to select the correct Local or First Nation Government jurisdiction and re-submit the application. - - - If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - ${notificationOnly} - - - - ${portalButton} - - ${footer()} - - -`; - -export const generateWRNGHtml = (data: StatusUpdateEmail): MJMLParseResults => { - return new EmailTemplateService().generateEmailBase(template, data); -}; +import { build } from '.'; +import { notificationOnly } from './partials/notification-only.template'; + +export const template = build( + `

+ This email is to advise that the above noted {{ childType }} application does not fall within the jurisdiction of the {{ governmentName }} and consequently it has been returned to the applicant. +

+

+ Please login to the ALC Portal to select the correct Local or First Nation Government jurisdiction and re-submit the application. +

+

+ If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. +

+ ${notificationOnly}`, +); From 9e558d9053b2ccc1c5a77593ea910c31206e52f7 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 10 Sep 2024 08:48:50 -0700 Subject: [PATCH 11/20] Recreate templates --- .../emails/partials/footer.template.ts | 22 ++++++++++++-- .../emails/partials/header.template.ts | 30 +++++++++---------- .../emails/partials/masthead.template.ts | 22 ++++++++++++++ .../emails/partials/portal-button.template.ts | 2 +- .../emails/refused-to-forward.template.ts | 16 +++++----- .../submitted-to-alc/application.template.ts | 2 +- .../noi-applicant.template.ts | 2 +- .../tur-applicant.template.ts | 2 +- .../submitted-to-lfng/applicant.template.ts | 2 +- .../submitted-to-lfng/government.template.ts | 2 +- 10 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 services/templates/emails/partials/masthead.template.ts diff --git a/services/templates/emails/partials/footer.template.ts b/services/templates/emails/partials/footer.template.ts index 5a2b745ffb..5c530b2693 100644 --- a/services/templates/emails/partials/footer.template.ts +++ b/services/templates/emails/partials/footer.template.ts @@ -1,9 +1,25 @@ import { v4 } from 'uuid'; export const footer = ` - Provincial Agricultural Land Commission (gov.bc.ca) - Contact: 604-660-7000 - ${v4()} + + + + + + + +
+ Provincial Agricultural Land Commission (gov.bc.ca) + + Contact: 604-660-7000 +
+ + ${v4()} + `; diff --git a/services/templates/emails/partials/header.template.ts b/services/templates/emails/partials/header.template.ts index 74849d9d10..7761a42de6 100644 --- a/services/templates/emails/partials/header.template.ts +++ b/services/templates/emails/partials/header.template.ts @@ -1,18 +1,18 @@ -import * as config from 'config'; +import { masthead } from './masthead.template'; export const header = ` - - - - - - Document - - - {{ parentTypeLabel }} ID #{{ fileNumber }} - Name: {{ applicantName }} - Status: {{ status }} - + + + + + + Document + + + + +
+ ${masthead} `; diff --git a/services/templates/emails/partials/masthead.template.ts b/services/templates/emails/partials/masthead.template.ts new file mode 100644 index 0000000000..cd5f6ce775 --- /dev/null +++ b/services/templates/emails/partials/masthead.template.ts @@ -0,0 +1,22 @@ +import * as config from 'config'; + +export const masthead = ` + + + + + +
+

{{ parentTypeLabel }} ID #{{ fileNumber }}

+

Name: {{ applicantName }}

+

Status: {{ status }}

+
+ + + + +
+ +
+
+`; diff --git a/services/templates/emails/partials/portal-button.template.ts b/services/templates/emails/partials/portal-button.template.ts index 8c8f358a61..699d88ea4e 100644 --- a/services/templates/emails/partials/portal-button.template.ts +++ b/services/templates/emails/partials/portal-button.template.ts @@ -1,5 +1,5 @@ import * as config from 'config'; export const portalButton = ` - GO TO ALC PORTAL + GO TO ALC PORTAL `; diff --git a/services/templates/emails/refused-to-forward.template.ts b/services/templates/emails/refused-to-forward.template.ts index efb1d68bba..48096122bf 100644 --- a/services/templates/emails/refused-to-forward.template.ts +++ b/services/templates/emails/refused-to-forward.template.ts @@ -2,17 +2,17 @@ import { build } from '.'; import { notificationOnly } from './partials/notification-only.template'; export const template = build( - ` + `

This email is to advise that the above noted {{ childType }} application has been reviewed by the {{ governmentName }} which has determined not to forward your application to the Agricultural Land Commission for further review. - - +

+

If you have any questions about this outcome, please contact {{ governmentName }}. - - +

+

If you are an agent acting on behalf of the applicant(s)/landowner(s), it is your responsibility to advise your client(s) of this, and any future, correspondence. - - +

+

Login to the ALC Portal for further information on your application. - +

${notificationOnly}`, ); diff --git a/services/templates/emails/submitted-to-alc/application.template.ts b/services/templates/emails/submitted-to-alc/application.template.ts index b222335710..00e7d4b87d 100644 --- a/services/templates/emails/submitted-to-alc/application.template.ts +++ b/services/templates/emails/submitted-to-alc/application.template.ts @@ -9,7 +9,7 @@ export const template = build(

APPLICATION FEES - Payable to the Minister of Finance c/o the ALC

- +
diff --git a/services/templates/emails/submitted-to-alc/noi-applicant.template.ts b/services/templates/emails/submitted-to-alc/noi-applicant.template.ts index e7dd98507a..bdad543e67 100644 --- a/services/templates/emails/submitted-to-alc/noi-applicant.template.ts +++ b/services/templates/emails/submitted-to-alc/noi-applicant.template.ts @@ -14,7 +14,7 @@ export const template = build(

NOTICE OF INTENT FEES - Payable to the Minister of Finance c/o the ALC

-
Application Type ALC Portion of Fee
+
diff --git a/services/templates/emails/submitted-to-alc/tur-applicant.template.ts b/services/templates/emails/submitted-to-alc/tur-applicant.template.ts index 99c34b7bd3..c86a93676b 100644 --- a/services/templates/emails/submitted-to-alc/tur-applicant.template.ts +++ b/services/templates/emails/submitted-to-alc/tur-applicant.template.ts @@ -8,7 +8,7 @@ export const template = build(

APPLICATION FEES - Payable to the Minister of Finance c/o the ALC

-
NOI Type ALC Portion of Fee
+
diff --git a/services/templates/emails/submitted-to-lfng/applicant.template.ts b/services/templates/emails/submitted-to-lfng/applicant.template.ts index c5dcea267f..64b92c6108 100644 --- a/services/templates/emails/submitted-to-lfng/applicant.template.ts +++ b/services/templates/emails/submitted-to-lfng/applicant.template.ts @@ -12,7 +12,7 @@ export const appFees = [ export const template = build(`

This email is to acknowledge that you have submitted the above noted {{ childType }} application to the {{ governmentName }}. -

Application Type Application Fee
+
diff --git a/services/templates/emails/submitted-to-lfng/government.template.ts b/services/templates/emails/submitted-to-lfng/government.template.ts index 5eb5052a97..553a3b1215 100644 --- a/services/templates/emails/submitted-to-lfng/government.template.ts +++ b/services/templates/emails/submitted-to-lfng/government.template.ts @@ -6,7 +6,7 @@ export const template = build( `

Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the {{ governmentName }}. The Applicant has been instructed to contact the {{ governmentName }} for payment instructions regarding the applicable application fee.

-
Application Type {{ governmentName }} Portion of Fee
+
From 421b5fe51c7dee63626b226dd570271f5b6d9700 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 10 Sep 2024 12:00:11 -0700 Subject: [PATCH 12/20] Move fees table to partial --- .../emails/partials/fees-table.template.ts | 17 +++++++++++++++++ .../submitted-to-alc/application.template.ts | 18 ++---------------- .../submitted-to-alc/noi-applicant.template.ts | 18 ++---------------- .../submitted-to-alc/tur-applicant.template.ts | 16 ++++++---------- .../submitted-to-lfng/applicant.template.ts | 18 ++---------------- .../submitted-to-lfng/government.template.ts | 18 ++---------------- 6 files changed, 31 insertions(+), 74 deletions(-) create mode 100644 services/templates/emails/partials/fees-table.template.ts diff --git a/services/templates/emails/partials/fees-table.template.ts b/services/templates/emails/partials/fees-table.template.ts new file mode 100644 index 0000000000..5e7294c072 --- /dev/null +++ b/services/templates/emails/partials/fees-table.template.ts @@ -0,0 +1,17 @@ +export const feesTable = (typeHeading: string, feeHeading: string, feeData) => + `
Application Type {{ governmentName }} Portion of Fee
+ + + + + ${feeData + .map(({ type, fee }) => { + return ` + + + + + `; + }) + .join('')} +
${typeHeading}${feeHeading}
${type}$${fee}
`; diff --git a/services/templates/emails/submitted-to-alc/application.template.ts b/services/templates/emails/submitted-to-alc/application.template.ts index 00e7d4b87d..0003eb6146 100644 --- a/services/templates/emails/submitted-to-alc/application.template.ts +++ b/services/templates/emails/submitted-to-alc/application.template.ts @@ -1,4 +1,5 @@ import { build } from '..'; +import { feesTable } from '../partials/fees-table.template'; import { notificationOnly } from '../partials/notification-only.template'; import { appFees } from '../submitted-to-lfng/applicant.template'; @@ -9,22 +10,7 @@ export const template = build(

APPLICATION FEES - Payable to the Minister of Finance c/o the ALC

- - - - - - ${appFees - .map((a) => { - return ` - - - - - `; - }) - .join('')} -
Application TypeALC Portion of Fee
${a.type}$${a.fee}
+ ${feesTable('Application Type', 'ALC Portion of Fee', appFees)}

This fee can be paid:

    diff --git a/services/templates/emails/submitted-to-alc/noi-applicant.template.ts b/services/templates/emails/submitted-to-alc/noi-applicant.template.ts index bdad543e67..e90e99b813 100644 --- a/services/templates/emails/submitted-to-alc/noi-applicant.template.ts +++ b/services/templates/emails/submitted-to-alc/noi-applicant.template.ts @@ -1,4 +1,5 @@ import { build } from '..'; +import { feesTable } from '../partials/fees-table.template'; import { notificationOnly } from '../partials/notification-only.template'; const noiFees = [ @@ -14,22 +15,7 @@ export const template = build(

    NOTICE OF INTENT FEES - Payable to the Minister of Finance c/o the ALC

    - - - - - - ${noiFees - .map((a) => { - return ` - - - - - `; - }) - .join('')} -
    NOI TypeALC Portion of Fee
    ${a.type}$${a.fee}
    + ${feesTable('NOI Type', 'Fee', noiFees)}

    This fee can be paid:

      diff --git a/services/templates/emails/submitted-to-alc/tur-applicant.template.ts b/services/templates/emails/submitted-to-alc/tur-applicant.template.ts index c86a93676b..8a23ae5e1c 100644 --- a/services/templates/emails/submitted-to-alc/tur-applicant.template.ts +++ b/services/templates/emails/submitted-to-alc/tur-applicant.template.ts @@ -1,6 +1,11 @@ import { build } from '..'; +import { feesTable } from '../partials/fees-table.template'; import { notificationOnly } from '../partials/notification-only.template'; +const turFees = [ + { type: 'Transportation, Utility, and Recreational Trail Uses', fee: 1500 }, +]; + export const template = build( `

      This email is to acknowledge that the Agricultural Land Commission (ALC) is in receipt of the above noted {{ childType }} application. Please refer to the ALC Application ID in all future correspondence with this office. A copy of this application has been forwarded to the {{ governmentName }} for information purposes. @@ -8,16 +13,7 @@ export const template = build(

      APPLICATION FEES - Payable to the Minister of Finance c/o the ALC

      - - - - - - - - - -
      Application TypeApplication Fee
      Transportation, Utility, and Recreational Trail Uses$1500
      + ${feesTable('Application Type', 'Application Fee', turFees)}

      This fee can be paid:

        diff --git a/services/templates/emails/submitted-to-lfng/applicant.template.ts b/services/templates/emails/submitted-to-lfng/applicant.template.ts index 64b92c6108..a55833e5d5 100644 --- a/services/templates/emails/submitted-to-lfng/applicant.template.ts +++ b/services/templates/emails/submitted-to-lfng/applicant.template.ts @@ -1,4 +1,5 @@ import { build } from '..'; +import { feesTable } from '../partials/fees-table.template'; import { notificationOnly } from '../partials/notification-only.template'; export const appFees = [ @@ -12,22 +13,7 @@ export const appFees = [ export const template = build(`

        This email is to acknowledge that you have submitted the above noted {{ childType }} application to the {{ governmentName }}. - - - - - - ${appFees - .map((a) => { - return ` - - - - - `; - }) - .join('')} -
        Application Type{{ governmentName }} Portion of Fee
        ${a.type}$${a.fee}
        +${feesTable('Application Type', '{{ governmentName }} Portion of Fee', appFees)}

        Contact the {{ governmentName }} for its payment options. Please include your assigned Application ID with your payment.

        diff --git a/services/templates/emails/submitted-to-lfng/government.template.ts b/services/templates/emails/submitted-to-lfng/government.template.ts index 553a3b1215..ff87f1e6e0 100644 --- a/services/templates/emails/submitted-to-lfng/government.template.ts +++ b/services/templates/emails/submitted-to-lfng/government.template.ts @@ -1,4 +1,5 @@ import { build } from '..'; +import { feesTable } from '../partials/fees-table.template'; import { notificationOnly } from '../partials/notification-only.template'; import { appFees } from './applicant.template'; @@ -6,22 +7,7 @@ export const template = build( `

        Agricultural Land Commission {{ childType }} Application ID: {{ fileNumber }} ({{ applicantName }}) has been successfully submitted to the {{ governmentName }}. The Applicant has been instructed to contact the {{ governmentName }} for payment instructions regarding the applicable application fee.

        - - - - - - ${appFees - .map((a) => { - return ` - - - - - `; - }) - .join('')} -
        Application Type{{ governmentName }} Portion of Fee
        ${a.type}$${a.fee}
        + ${feesTable('Application Type', '{{ governmentName }} Portion of Fee', appFees)}

        Please log into the ALC Portal to view the application.

        From 6fd0d2bcb948fb68af4b2c2e32c1e9989b1ba3c6 Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:08:22 -0700 Subject: [PATCH 13/20] Fix notification emails missing type label --- .../notification-submission/notification-submission.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts b/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts index f31aa220fb..05bdc504ae 100644 --- a/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts +++ b/services/apps/alcs/src/portal/notification-submission/notification-submission.service.ts @@ -464,6 +464,7 @@ export class NotificationSubmissionService { ); const html = compile(template)({ + parentTypeLabel: 'Notification', fileNumber: submission.fileNumber, contactName: `${submission.contactFirstName} ${submission.contactLastName}`, status: 'ALC Response Sent', From e35407fab0a01526401da501f7250e3f7a9f619b Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Wed, 11 Sep 2024 08:43:47 -0700 Subject: [PATCH 14/20] Fix tests --- .../application.controller.spec.ts | 4 ++-- ...ation-submission-review.controller.spec.ts | 16 ++++++------- .../application-submission.controller.spec.ts | 24 ++++++++----------- ...ce-of-intent-submission.controller.spec.ts | 10 ++++---- .../email/status-email.service.spec.ts | 7 +++--- .../decision-emails.consumer.spec.ts | 4 ++-- .../status-emails.consumer.spec.ts | 4 ++-- .../decision-emails.consumer.spec.ts | 4 ++-- 8 files changed, 33 insertions(+), 40 deletions(-) diff --git a/services/apps/alcs/src/alcs/application/application.controller.spec.ts b/services/apps/alcs/src/alcs/application/application.controller.spec.ts index f405cb677a..a357a686be 100644 --- a/services/apps/alcs/src/alcs/application/application.controller.spec.ts +++ b/services/apps/alcs/src/alcs/application/application.controller.spec.ts @@ -4,7 +4,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { classes } from 'automapper-classes'; import { AutomapperModule } from 'automapper-nestjs'; import { ClsService } from 'nestjs-cls'; -import { generateCANCApplicationHtml } from '../../../../../templates/emails/cancelled'; +import { template } from '../../../../../templates/emails/cancelled/application.template'; import { initApplicationMockEntity, initMockAssigneeDto, @@ -426,7 +426,7 @@ describe('ApplicationController', () => { 1, ); expect(statusEmailService.sendApplicationStatusEmail).toHaveBeenCalledWith({ - generateStatusHtml: generateCANCApplicationHtml, + template, status: SUBMISSION_STATUS.CANCELLED, applicationSubmission: mockApplicationSubmission, government: mockGovernment, diff --git a/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.spec.ts b/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.spec.ts index c478ea8e8b..1f148e110d 100644 --- a/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.spec.ts +++ b/services/apps/alcs/src/portal/application-submission-review/application-submission-review.controller.spec.ts @@ -2,10 +2,10 @@ import { BaseServiceException } from '@app/common/exceptions/base.exception'; import { createMock, DeepMocked } from '@golevelup/nestjs-testing'; import { Test, TestingModule } from '@nestjs/testing'; import { ClsService } from 'nestjs-cls'; -import { generateRFFGHtml } from '../../../../../templates/emails/refused-to-forward.template'; -import { generateINCMHtml } from '../../../../../templates/emails/returned-as-incomplete.template'; -import { generateSUBMApplicationHtml } from '../../../../../templates/emails/submitted-to-alc'; -import { generateWRNGHtml } from '../../../../../templates/emails/wrong-lfng.template'; +import { template as rffgTemplate } from '../../../../../templates/emails/refused-to-forward.template'; +import { template as incmTemplate } from '../../../../../templates/emails/returned-as-incomplete.template'; +import { template as submApplicationTemplate } from '../../../../../templates/emails/submitted-to-alc/application.template'; +import { template as wrngTemplate } from '../../../../../templates/emails/wrong-lfng.template'; import { mockKeyCloakProviders } from '../../../test/mocks/mockTypes'; import { ApplicationDocument } from '../../alcs/application/application-document/application-document.entity'; import { ApplicationDocumentService } from '../../alcs/application/application-document/application-document.service'; @@ -381,7 +381,7 @@ describe('ApplicationSubmissionReviewController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateSUBMApplicationHtml, + template: submApplicationTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_ALC, applicationSubmission: mockSubmission, government: mockLG, @@ -456,7 +456,7 @@ describe('ApplicationSubmissionReviewController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateRFFGHtml, + template: rffgTemplate, status: SUBMISSION_STATUS.REFUSED_TO_FORWARD_LG, applicationSubmission: mockSubmission, government: mockLG, @@ -559,7 +559,7 @@ describe('ApplicationSubmissionReviewController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateINCMHtml, + template: incmTemplate, status: SUBMISSION_STATUS.INCOMPLETE, applicationSubmission: mockSubmission, government: mockLG, @@ -638,7 +638,7 @@ describe('ApplicationSubmissionReviewController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateWRNGHtml, + template: wrngTemplate, status: SUBMISSION_STATUS.WRONG_GOV, applicationSubmission: mockSubmission, government: mockLG, diff --git a/services/apps/alcs/src/portal/application-submission/application-submission.controller.spec.ts b/services/apps/alcs/src/portal/application-submission/application-submission.controller.spec.ts index b38578711d..5187dd10f1 100644 --- a/services/apps/alcs/src/portal/application-submission/application-submission.controller.spec.ts +++ b/services/apps/alcs/src/portal/application-submission/application-submission.controller.spec.ts @@ -5,15 +5,11 @@ import { classes } from 'automapper-classes'; import { AutomapperModule } from 'automapper-nestjs'; import { ClsService } from 'nestjs-cls'; import { ServiceValidationException } from '../../../../../libs/common/src/exceptions/base.exception'; -import { generateCANCApplicationHtml } from '../../../../../templates/emails/cancelled'; -import { - generateSUBGNoReviewGovernmentTemplateEmail, - generateSUBGTurApplicantHtml, -} from '../../../../../templates/emails/submitted-to-alc'; -import { - generateSUBGApplicantHtml, - generateSUBGGovernmentHtml, -} from '../../../../../templates/emails/submitted-to-lfng'; +import { template as cancApplicationTemplate } from '../../../../../templates/emails/cancelled/application.template'; +import { template as subgNoReviewGovernmentTemplate } from '../../../../../templates/emails/submitted-to-alc/no-review-government.template'; +import { template as subgTurApplicantTemplate } from '../../../../../templates/emails/submitted-to-alc/tur-applicant.template'; +import { template as subgApplicantTemplate } from '../../../../../templates/emails/submitted-to-lfng/applicant.template'; +import { template as subgGovernmentTemplate } from '../../../../../templates/emails/submitted-to-lfng/government.template'; import { mockKeyCloakProviders } from '../../../test/mocks/mockTypes'; import { ApplicationDocumentService } from '../../alcs/application/application-document/application-document.service'; import { ApplicationSubmissionStatusType } from '../../alcs/application/application-submission-status/submission-status-type.entity'; @@ -289,7 +285,7 @@ describe('ApplicationSubmissionController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateCANCApplicationHtml, + template: cancApplicationTemplate, status: SUBMISSION_STATUS.CANCELLED, applicationSubmission: mockApplication, government: mockGovernment, @@ -531,7 +527,7 @@ describe('ApplicationSubmissionController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateSUBGTurApplicantHtml, + template: subgTurApplicantTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_ALC, applicationSubmission: mockApplicationSubmission, government: mockGovernment, @@ -542,7 +538,7 @@ describe('ApplicationSubmissionController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateSUBGNoReviewGovernmentTemplateEmail, + template: subgNoReviewGovernmentTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_ALC, applicationSubmission: mockApplicationSubmission, government: mockGovernment, @@ -595,7 +591,7 @@ describe('ApplicationSubmissionController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateSUBGApplicantHtml, + template: subgApplicantTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_LG, applicationSubmission: mockApplicationSubmission, government: mockGovernment, @@ -606,7 +602,7 @@ describe('ApplicationSubmissionController', () => { expect( mockStatusEmailService.sendApplicationStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateSUBGGovernmentHtml, + template: subgGovernmentTemplate, status: SUBMISSION_STATUS.SUBMITTED_TO_LG, applicationSubmission: mockApplicationSubmission, government: mockGovernment, diff --git a/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.spec.ts b/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.spec.ts index 25872fffc6..ca45f4f055 100644 --- a/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.spec.ts +++ b/services/apps/alcs/src/portal/notice-of-intent-submission/notice-of-intent-submission.controller.spec.ts @@ -4,10 +4,8 @@ import { Test, TestingModule } from '@nestjs/testing'; import { classes } from 'automapper-classes'; import { AutomapperModule } from 'automapper-nestjs'; import { ClsService } from 'nestjs-cls'; -import { - generateSUBMNoiApplicantHtml, - generateSUBMNoiGovernmentHtml, -} from '../../../../../templates/emails/submitted-to-alc'; +import { template as submNoiApplicantTemplate } from '../../../../../templates/emails/submitted-to-alc/noi-applicant.template'; +import { template as submNoiGovernmentTemplate } from '../../../../../templates/emails/submitted-to-alc/noi-government.template'; import { mockKeyCloakProviders } from '../../../test/mocks/mockTypes'; import { LocalGovernment } from '../../alcs/local-government/local-government.entity'; import { LocalGovernmentService } from '../../alcs/local-government/local-government.service'; @@ -391,7 +389,7 @@ describe('NoticeOfIntentSubmissionController', () => { expect( mockStatusEmailService.sendNoticeOfIntentStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateSUBMNoiApplicantHtml, + template: submNoiApplicantTemplate, status: NOI_SUBMISSION_STATUS.SUBMITTED_TO_ALC, noticeOfIntentSubmission: mockSubmission, government: mockGovernment, @@ -402,7 +400,7 @@ describe('NoticeOfIntentSubmissionController', () => { expect( mockStatusEmailService.sendNoticeOfIntentStatusEmail, ).toHaveBeenCalledWith({ - generateStatusHtml: generateSUBMNoiGovernmentHtml, + template: submNoiGovernmentTemplate, status: NOI_SUBMISSION_STATUS.SUBMITTED_TO_ALC, noticeOfIntentSubmission: mockSubmission, government: mockGovernment, diff --git a/services/apps/alcs/src/providers/email/status-email.service.spec.ts b/services/apps/alcs/src/providers/email/status-email.service.spec.ts index 00238d5b5c..659d0ba78f 100644 --- a/services/apps/alcs/src/providers/email/status-email.service.spec.ts +++ b/services/apps/alcs/src/providers/email/status-email.service.spec.ts @@ -2,7 +2,6 @@ import { CONFIG_TOKEN, ConfigModule } from '@app/common/config/config.module'; import { createMock, DeepMocked } from '@golevelup/nestjs-testing'; import { Test, TestingModule } from '@nestjs/testing'; import * as config from 'config'; -import { MJMLParseResults } from 'mjml-core'; import { ApplicationDecisionDocument } from '../../alcs/application-decision/application-decision-document/application-decision-document.entity'; import { ApplicationDecisionV2Service } from '../../alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service'; import { ApplicationDecision } from '../../alcs/application-decision/application-decision.entity'; @@ -225,7 +224,7 @@ describe('StatusEmailService', () => { it('should call through services to set application email template', async () => { const mockData: ApplicationEmailData = { - generateStatusHtml: () => ({}) as MJMLParseResults, + template: 'test', status: SUBMISSION_STATUS.IN_REVIEW_BY_LG, applicationSubmission: new ApplicationSubmission({ typeCode: 'TURP' }), parentType: 'application' as PARENT_TYPE, @@ -251,7 +250,7 @@ describe('StatusEmailService', () => { it('should call through services to set notice of intent email template', async () => { const mockData: NoticeOfIntentEmailData = { - generateStatusHtml: () => ({}) as MJMLParseResults, + template: 'test', status: NOI_SUBMISSION_STATUS.SUBMITTED_TO_ALC, noticeOfIntentSubmission: new NoticeOfIntentSubmission(), parentType: 'notice-of-intent' as PARENT_TYPE, @@ -280,7 +279,7 @@ describe('StatusEmailService', () => { it('should add CC emails to the send call', async () => { const ccEmails = ['bruce.wayne@fakeemail.com', 'iam.batman@fakeemail.com']; const mockData: NoticeOfIntentEmailData = { - generateStatusHtml: () => ({}) as MJMLParseResults, + template: 'test', status: NOI_SUBMISSION_STATUS.SUBMITTED_TO_ALC, noticeOfIntentSubmission: new NoticeOfIntentSubmission(), parentType: 'notice-of-intent' as PARENT_TYPE, diff --git a/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.spec.ts b/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.spec.ts index 3b45f3d0fe..8017f23d35 100644 --- a/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.spec.ts +++ b/services/apps/alcs/src/queues/scheduler/application/decision-emails/decision-emails.consumer.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/nestjs-testing'; import { Test, TestingModule } from '@nestjs/testing'; -import { generateALCDApplicationHtml } from '../../../../../../../templates/emails/decision-released'; +import { template } from '../../../../../../../templates/emails/decision-released/application.template'; import { ApplicationDecisionV2Service } from '../../../../alcs/application-decision/application-decision-v2/application-decision/application-decision-v2.service'; import { ApplicationDecision } from '../../../../alcs/application-decision/application-decision.entity'; import { ApplicationSubmissionStatusService } from '../../../../alcs/application/application-submission-status/application-submission-status.service'; @@ -121,7 +121,7 @@ describe('ApplicationDecisionEmailConsumer', () => { parentType: PARENT_TYPE.APPLICATION, primaryContact: mockPrimaryContact, ccGovernment: true, - generateStatusHtml: generateALCDApplicationHtml, + template, status: SUBMISSION_STATUS.ALC_DECISION, documents: mockDocuments, }); diff --git a/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.spec.ts b/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.spec.ts index f0147cdb4d..783a81123e 100644 --- a/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.spec.ts +++ b/services/apps/alcs/src/queues/scheduler/application/status-emails/status-emails.consumer.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/nestjs-testing'; import { Test, TestingModule } from '@nestjs/testing'; -import { generateREVAHtml } from '../../../../../../../templates/emails/under-review-by-alc.template'; +import { template } from '../../../../../../../templates/emails/under-review-by-alc.template'; import { ApplicationSubmissionStatusService } from '../../../../alcs/application/application-submission-status/application-submission-status.service'; import { SUBMISSION_STATUS } from '../../../../alcs/application/application-submission-status/submission-status.dto'; import { ApplicationSubmissionToSubmissionStatus } from '../../../../alcs/application/application-submission-status/submission-status.entity'; @@ -102,7 +102,7 @@ describe('ApplicationSubmissionStatusEmailConsumer', () => { parentType: PARENT_TYPE.APPLICATION, primaryContact: mockPrimaryContact, ccGovernment: true, - generateStatusHtml: generateREVAHtml, + template, status: SUBMISSION_STATUS.IN_REVIEW_BY_ALC, documents: [], ccEmails: [], diff --git a/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.spec.ts b/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.spec.ts index fde64828d9..1ae8df3154 100644 --- a/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.spec.ts +++ b/services/apps/alcs/src/queues/scheduler/notice-of-intent/decision-emails.consumer.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/nestjs-testing'; import { Test, TestingModule } from '@nestjs/testing'; -import { generateALCDNoticeOfIntentHtml } from '../../../../../../templates/emails/decision-released'; +import { template } from '../../../../../../templates/emails/decision-released/notice-of-intent.template'; import { PARENT_TYPE } from '../../../alcs/card/card-subtask/card-subtask.dto'; import { LocalGovernment } from '../../../alcs/local-government/local-government.entity'; import { NoticeOfIntentDecisionV2Service } from '../../../alcs/notice-of-intent-decision/notice-of-intent-decision-v2/notice-of-intent-decision-v2.service'; @@ -108,7 +108,7 @@ describe('NoticeOfIntentDecisionEmailsConsumer', () => { parentType: PARENT_TYPE.NOTICE_OF_INTENT, primaryContact: mockPrimaryContact, ccGovernment: true, - generateStatusHtml: generateALCDNoticeOfIntentHtml, + template, status: NOI_SUBMISSION_STATUS.ALC_DECISION, documents: mockDocuments, }); From ecd372a2555d2724ac3b1c0a5d3f5ba9e8a446ef Mon Sep 17 00:00:00 2001 From: Tristan Slater <1631008+trslater@users.noreply.github.com> Date: Wed, 11 Sep 2024 10:39:48 -0700 Subject: [PATCH 15/20] Show goto button on incoming files' details page --- .../details-header.component.html | 2 +- .../details-header.component.ts | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/alcs-frontend/src/app/shared/details-header/details-header.component.html b/alcs-frontend/src/app/shared/details-header/details-header.component.html index 7f684ccb4f..f6fe65a477 100644 --- a/alcs-frontend/src/app/shared/details-header/details-header.component.html +++ b/alcs-frontend/src/app/shared/details-header/details-header.component.html @@ -39,7 +39,7 @@