From 8d8216ea9cdb4dea9f71a960403a25e1482e1aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dziuba?= Date: Wed, 15 Nov 2023 14:11:20 +0100 Subject: [PATCH] feat(worker): add handlebar helper for number formatting (#4827) * feat: add handlebar helper for number formating * refactor: improve number format helper readability --- .../handlebar-helpers/handlebarHelpers.ts | 2 + .../compile-template/compile-template.spec.ts | 39 ++++++++++++++----- .../compile-template.usecase.ts | 25 ++++++++++++ 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/libs/shared/src/consts/handlebar-helpers/handlebarHelpers.ts b/libs/shared/src/consts/handlebar-helpers/handlebarHelpers.ts index 9894fc8f8b2..6807de92a2d 100644 --- a/libs/shared/src/consts/handlebar-helpers/handlebarHelpers.ts +++ b/libs/shared/src/consts/handlebar-helpers/handlebarHelpers.ts @@ -8,6 +8,7 @@ export enum HandlebarHelpersEnum { UNIQUE = 'unique', GROUP_BY = 'groupBy', SORT_BY = 'sortBy', + NUMBERFORMAT = 'numberFormat', } // eslint-disable-next-line @typescript-eslint/naming-convention @@ -21,4 +22,5 @@ export const HandlebarHelpers = { [HandlebarHelpersEnum.UNIQUE]: { description: 'filter unique values in an array' }, [HandlebarHelpersEnum.GROUP_BY]: { description: 'group by a property' }, [HandlebarHelpersEnum.SORT_BY]: { description: 'sort an array of objects by a property' }, + [HandlebarHelpersEnum.NUMBERFORMAT]: { description: 'format number' }, }; diff --git a/packages/application-generic/src/usecases/compile-template/compile-template.spec.ts b/packages/application-generic/src/usecases/compile-template/compile-template.spec.ts index fd70db36918..4003ac48f29 100644 --- a/packages/application-generic/src/usecases/compile-template/compile-template.spec.ts +++ b/packages/application-generic/src/usecases/compile-template/compile-template.spec.ts @@ -1,22 +1,17 @@ import { Test } from '@nestjs/testing'; -import { UserSession } from '@novu/testing'; import { CompileTemplate } from './compile-template.usecase'; import { CompileTemplateCommand } from './compile-template.command'; describe('Compile Template', function () { let useCase: CompileTemplate; - let session: UserSession; beforeEach(async () => { const moduleRef = await Test.createTestingModule({ - imports: [CompileTemplate], - providers: [], + imports: [], + providers: [CompileTemplate], }).compile(); - session = new UserSession(); - await session.initialize(); - useCase = moduleRef.get(CompileTemplate); }); @@ -88,11 +83,11 @@ describe('Compile Template', function () { ], }, template: - '{{#each (groupby names "name")}}

{{key}}

{{#each items}}{{age}}-{{/each}}{{/each}}>', + '{{#each (groupBy names "name")}}

{{key}}

{{#each items}}{{age}}-{{/each}}{{/each}}', }) ); - expect(result).toEqual('

Name1

30-32-

Name2

31-'); + expect(result).toEqual('

Name 1

30-32-

Name 2

31-'); }); it('should render sortBy values of array', async function () { @@ -188,4 +183,30 @@ describe('Compile Template', function () { expect(result).toEqual('
ABCD
'); }); }); + + describe('Number formating', () => { + it('should format number', async () => { + const result = await useCase.execute( + CompileTemplateCommand.create({ + data: { number: 1000000000 }, + template: + '
{{numberFormat number decimalSep="," decimalLength="2" thousandsSep="|"}}
', + }) + ); + + expect(result).toEqual('
1|000|000|000,00
'); + }); + + it('should not fail and return passed value', async () => { + const result = await useCase.execute( + CompileTemplateCommand.create({ + data: { number: 'Not a number' }, + template: + '
{{numberFormat number decimalSep="," decimalLength="2" thousandsSep="|"}}
', + }) + ); + + expect(result).toEqual('
Not a number
'); + }); + }); }); diff --git a/packages/application-generic/src/usecases/compile-template/compile-template.usecase.ts b/packages/application-generic/src/usecases/compile-template/compile-template.usecase.ts index f8bd3898e3c..e529024e0c8 100644 --- a/packages/application-generic/src/usecases/compile-template/compile-template.usecase.ts +++ b/packages/application-generic/src/usecases/compile-template/compile-template.usecase.ts @@ -105,6 +105,31 @@ Handlebars.registerHelper( } ); +// based on: https://gist.github.com/DennyLoko/61882bc72176ca74a0f2 +Handlebars.registerHelper( + HandlebarHelpersEnum.NUMBERFORMAT, + function (number, options) { + if (isNaN(number)) { + return number; + } + + const decimalLength = options.hash.decimalLength || 2; + const thousandsSep = options.hash.thousandsSep || ','; + const decimalSep = options.hash.decimalSep || '.'; + + const value = parseFloat(number); + + const re = '\\d(?=(\\d{3})+' + (decimalLength > 0 ? '\\D' : '$') + ')'; + + const num = value.toFixed(Math.max(0, ~~decimalLength)); + + return (decimalSep ? num.replace('.', decimalSep) : num).replace( + new RegExp(re, 'g'), + '$&' + thousandsSep + ); + } +); + @Injectable() export class CompileTemplate { async execute(command: CompileTemplateCommand): Promise {