diff --git a/services/API-service/src/api/metadata/dto/add-indicators.dto.ts b/services/API-service/src/api/metadata/dto/add-indicators.dto.ts index e0029e2d2..4d00cf3e5 100644 --- a/services/API-service/src/api/metadata/dto/add-indicators.dto.ts +++ b/services/API-service/src/api/metadata/dto/add-indicators.dto.ts @@ -8,6 +8,8 @@ import { IsString, } from 'class-validator'; +import { NumberFormat } from '../../../shared/enums/number-format.enum'; + export class IndicatorDto { @ApiProperty({ example: { @@ -53,9 +55,9 @@ export class IndicatorDto { }) public colorBreaks: JSON; - @ApiProperty({ example: 'decimal0' }) + @ApiProperty({ example: NumberFormat.decimal0 }) @IsString() - public numberFormatMap: string; + public numberFormatMap: NumberFormat; @ApiProperty({ example: 'decimal0' }) @IsIn(['decimal0', 'decimal2', 'perc']) diff --git a/services/API-service/src/api/metadata/indicator-metadata.entity.ts b/services/API-service/src/api/metadata/indicator-metadata.entity.ts index ce8ab7512..bf60318e6 100644 --- a/services/API-service/src/api/metadata/indicator-metadata.entity.ts +++ b/services/API-service/src/api/metadata/indicator-metadata.entity.ts @@ -2,6 +2,8 @@ import { ApiProperty } from '@nestjs/swagger'; import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; +import { NumberFormat } from '../../shared/enums/number-format.enum'; + @Entity('indicator-metadata') export class IndicatorMetadataEntity { @ApiProperty({ example: '6b9b7669-4839-4fdb-9645-9070a27bda86' }) @@ -49,9 +51,9 @@ export class IndicatorMetadataEntity { @Column('json', { nullable: true }) public colorBreaks: JSON; - @ApiProperty({ example: 'decimal0' }) + @ApiProperty({ example: NumberFormat.decimal0 }) @Column() - public numberFormatMap: string; + public numberFormatMap: NumberFormat; @ApiProperty({ example: 'decimal0' }) @Column() diff --git a/services/API-service/src/api/notification/email/email-template.service.ts b/services/API-service/src/api/notification/email/email-template.service.ts index 405a189ab..b53547902 100644 --- a/services/API-service/src/api/notification/email/email-template.service.ts +++ b/services/API-service/src/api/notification/email/email-template.service.ts @@ -9,6 +9,7 @@ import { EventSummaryCountry, TriggeredArea, } from '../../../shared/data.model'; +import { HelperService } from '../../../shared/helper.service'; import { LeadTime } from '../../admin-area-dynamic-data/enum/lead-time.enum'; import { CountryTimeZoneMapping } from '../../country/country-time-zone-mapping'; import { CountryEntity } from '../../country/country.entity'; @@ -26,6 +27,8 @@ const emailLogoFolder = `${emailFolder}/logos`; @Injectable() export class EmailTemplateService { + public constructor(private readonly helperService: HelperService) {} + public async createHtmlForTriggerEmail( emailContent: ContentEventEmail, date: Date, @@ -303,7 +306,9 @@ export class EmailTemplateService { .map((area) => { const areaTemplate = this.readHtmlFile('table-row.html'); const areaData = { - affectedOfIndicator: area.actionsValue, + affectedOfIndicator: this.helperService.toCompactNumber( + area.actionsValue, + ), adminBoundary: area.displayName ? area.displayName : area.name, higherAdminBoundary: area.nameParent, }; @@ -414,7 +419,9 @@ export class EmailTemplateService { : 'body-total-affected-unavailable.html'; const htmlTemplate = this.readHtmlFile(fileName); return ejs.render(htmlTemplate, { - totalAffectedOfIndicator: event.totalAffectedOfIndicator, + totalAffectedOfIndicator: this.helperService.toCompactNumber( + event.totalAffectedOfIndicator, + ), indicatorUnit: indicatorUnit, }); } diff --git a/services/API-service/src/api/notification/email/html/body-total-affected-available.html b/services/API-service/src/api/notification/email/html/body-total-affected-available.html index e5f37e53d..3086099c3 100644 --- a/services/API-service/src/api/notification/email/html/body-total-affected-available.html +++ b/services/API-service/src/api/notification/email/html/body-total-affected-available.html @@ -1,4 +1,4 @@ - <%= totalAffectedOfIndicator %> <%= indicatorUnit %> + <%= totalAffectedOfIndicator %> <%= indicatorUnit %> (approx.) diff --git a/services/API-service/src/api/notification/email/html/header.html b/services/API-service/src/api/notification/email/html/header.html index 2e93f08d9..d8a9585b9 100644 --- a/services/API-service/src/api/notification/email/html/header.html +++ b/services/API-service/src/api/notification/email/html/header.html @@ -2,7 +2,7 @@ -
+

<%= nrOfEvents %> <%= disasterTypeLabel %> alerts

diff --git a/services/API-service/src/api/notification/email/html/styles.ejs b/services/API-service/src/api/notification/email/html/styles.ejs index 2c2d5b125..cf94f066b 100644 --- a/services/API-service/src/api/notification/email/html/styles.ejs +++ b/services/API-service/src/api/notification/email/html/styles.ejs @@ -25,6 +25,9 @@ .body-text-white { color: white; } + .body-text-grey { + color: #49515b; + } .body-text-12px { font-size: 12px; line-height: 14.4px; @@ -146,11 +149,4 @@ cellspacing: 0; cellpadding: 0; } - .centered-text { - text-align: center; - } - - .white-text { - color: white; - } diff --git a/services/API-service/src/api/notification/email/html/trigger-notification.html b/services/API-service/src/api/notification/email/html/trigger-notification.html index ae414f340..c1a052490 100644 --- a/services/API-service/src/api/notification/email/html/trigger-notification.html +++ b/services/API-service/src/api/notification/email/html/trigger-notification.html @@ -93,6 +93,13 @@ <%- mapImagePart %>

+
+ All numbers are approximate and meant to be used + as guidance. +
+
<%- tablesStacked %> <%- footer %> diff --git a/services/API-service/src/api/notification/helpers/format-action-unit-value.helper.ts b/services/API-service/src/api/notification/helpers/format-action-unit-value.helper.ts deleted file mode 100644 index ff365fd72..000000000 --- a/services/API-service/src/api/notification/helpers/format-action-unit-value.helper.ts +++ /dev/null @@ -1,16 +0,0 @@ -export function formatActionUnitValue( - value: number, - numberFormat: string, -): string { - if (value === null) { - return null; - } else if (numberFormat === 'perc') { - return Math.round(value * 100).toLocaleString() + '%'; - } else if (numberFormat === 'decimal2') { - return (Math.round(value * 100) / 100).toLocaleString(); - } else if (numberFormat === 'decimal0') { - return Math.round(value).toLocaleString(); - } else { - return Math.round(value).toLocaleString(); - } -} diff --git a/services/API-service/src/api/notification/notification.module.ts b/services/API-service/src/api/notification/notification.module.ts index 833c61d7b..3aacc55aa 100644 --- a/services/API-service/src/api/notification/notification.module.ts +++ b/services/API-service/src/api/notification/notification.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { HelperService } from '../../shared/helper.service'; import { IndicatorMetadataEntity } from '../metadata/indicator-metadata.entity'; import { TyphoonTrackModule } from '../typhoon-track/typhoon-track.module'; import { UserModule } from '../user/user.module'; @@ -25,6 +26,11 @@ import { WhatsappModule } from './whatsapp/whatsapp.module'; TyphoonTrackModule, ], controllers: [NotificationController], - providers: [NotificationService, EmailService, EmailTemplateService], + providers: [ + NotificationService, + EmailService, + EmailTemplateService, + HelperService, + ], }) export class NotificationModule {} diff --git a/services/API-service/src/api/notification/whatsapp/whatsapp.module.ts b/services/API-service/src/api/notification/whatsapp/whatsapp.module.ts index 653537e2e..271bc41ac 100644 --- a/services/API-service/src/api/notification/whatsapp/whatsapp.module.ts +++ b/services/API-service/src/api/notification/whatsapp/whatsapp.module.ts @@ -7,6 +7,7 @@ import { import { TypeOrmModule } from '@nestjs/typeorm'; import { API_PATHS } from '../../../config'; +import { HelperService } from '../../../shared/helper.service'; import { CountryEntity } from '../../country/country.entity'; import { EventMapImageEntity } from '../../event/event-map-image.entity'; import { EventModule } from '../../event/event.module'; @@ -30,7 +31,7 @@ import { WhatsappService } from './whatsapp.service'; EventModule, NotificationContentModule, ], - providers: [WhatsappService], + providers: [WhatsappService, HelperService], controllers: [WhatsappController], exports: [WhatsappService], }) diff --git a/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts b/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts index 681ff1699..30f3e26d5 100644 --- a/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts +++ b/services/API-service/src/api/notification/whatsapp/whatsapp.service.ts @@ -5,12 +5,12 @@ import { IsNull, Not, Repository } from 'typeorm'; import { EXTERNAL_API } from '../../../config'; import { EventSummaryCountry } from '../../../shared/data.model'; +import { HelperService } from '../../../shared/helper.service'; import { CountryEntity } from '../../country/country.entity'; import { DisasterType } from '../../disaster/disaster-type.enum'; import { EventMapImageEntity } from '../../event/event-map-image.entity'; import { EventService } from '../../event/event.service'; import { UserEntity } from '../../user/user.entity'; -import { formatActionUnitValue } from '../helpers/format-action-unit-value.helper'; import { LookupService } from '../lookup/lookup.service'; import { NotificationContentService } from '../notification-content/notification-content.service'; import { twilioClient } from './twilio.client'; @@ -35,6 +35,7 @@ export class WhatsappService { private readonly eventService: EventService, private readonly lookupService: LookupService, private readonly notificationContentService: NotificationContentService, + private readonly helperService: HelperService, ) {} public async sendTestWhatsapp( @@ -377,7 +378,7 @@ export class WhatsappService { for (const area of triggeredAreas) { const row = `- *${area.name}${ area.nameParent ? ' (' + area.nameParent + ')' : '' - } - ${formatActionUnitValue( + } - ${this.helperService.toCompactNumber( area.actionsValue, indicatorMetadata.numberFormatMap, )}*\n`; diff --git a/services/API-service/src/shared/enums/number-format.enum.ts b/services/API-service/src/shared/enums/number-format.enum.ts new file mode 100644 index 000000000..ae50fe826 --- /dev/null +++ b/services/API-service/src/shared/enums/number-format.enum.ts @@ -0,0 +1,5 @@ +export enum NumberFormat { + decimal0 = 'decimal0', + decimal2 = 'decimal2', + perc = 'perc', +} diff --git a/services/API-service/src/shared/helper.service.ts b/services/API-service/src/shared/helper.service.ts index a10e2c406..12f955365 100644 --- a/services/API-service/src/shared/helper.service.ts +++ b/services/API-service/src/shared/helper.service.ts @@ -11,6 +11,7 @@ import { import { DisasterType } from '../api/disaster/disaster-type.enum'; import { DateDto } from '../api/event/dto/date.dto'; import { TriggerPerLeadTime } from '../api/event/trigger-per-lead-time.entity'; +import { NumberFormat } from './enums/number-format.enum'; import { GeoJson, GeoJsonFeature } from './geo.model'; @Injectable() @@ -119,4 +120,21 @@ export class HelperService { }; } } + + public toCompactNumber( + value: number, + format: NumberFormat = NumberFormat.decimal0, + locale = 'en-GB', + ) { + const style = format === NumberFormat.perc ? 'percent' : 'decimal'; + const min = format === NumberFormat.perc ? 0.1 : 10; + + value = value > 0 ? Math.max(min, value) : 0; + + return new Intl.NumberFormat(locale, { + maximumSignificantDigits: 1, + style, + notation: 'compact', + }).format(value); + } }