diff --git a/src/notion/publish/format/formatValue.test.ts b/src/notion/publish/format/formatValue.test.ts new file mode 100644 index 0000000..f86f43e --- /dev/null +++ b/src/notion/publish/format/formatValue.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, test } from "@jest/globals"; +import { formatValue } from "./formatValue"; + +describe("formatValue", () => { + test("format with default options", () => { + expect(formatValue(42.42, { notionPropName: "whatever" })).toBe("42,4"); + expect(formatValue(42, { notionPropName: "whatever" })).toBe("42"); + }); + test("format with valueMaxFractioDigits: 2", () => { + expect( + formatValue(42.4242, { + notionPropName: "whatever", + valueMaxFractioDigits: 2, + }) + ).toBe("42,42"); + expect( + formatValue(42, { + notionPropName: "whatever", + valueMaxFractioDigits: 2, + }) + ).toBe("42"); + }); + + test("format with unit", () => { + expect( + formatValue(42, { + notionPropName: "whatever", + unit: "%", + }) + ).toBe("42%"); + }); +}); diff --git a/src/notion/publish/format/formatValue.ts b/src/notion/publish/format/formatValue.ts new file mode 100644 index 0000000..0abf439 --- /dev/null +++ b/src/notion/publish/format/formatValue.ts @@ -0,0 +1,15 @@ +import { StatPublishOptions } from "../../statPropsPublishOptions"; + +export function formatValue(value: number, publishOptions: StatPublishOptions) { + const valueStr = value.toLocaleString("fr-FR", { + useGrouping: false, + maximumFractionDigits: + publishOptions.valueMaxFractioDigits === undefined + ? 1 + : publishOptions.valueMaxFractioDigits, + }); + const formattedValue = `${valueStr}${ + publishOptions.unit === undefined ? "" : publishOptions.unit + }`; + return formattedValue; +} diff --git a/src/notion/publish/format/formatValueWithEvol.ts b/src/notion/publish/format/formatValueWithEvol.ts new file mode 100644 index 0000000..14283cc --- /dev/null +++ b/src/notion/publish/format/formatValueWithEvol.ts @@ -0,0 +1,33 @@ +import { ValueWithEvol } from "../../../statistiques/ELStats"; +import { StatPublishOptions } from "../../statPropsPublishOptions"; +import { formatValue } from "./formatValue"; + +export function formatValueWithEvol( + n: ValueWithEvol, + publishOptions: StatPublishOptions +): string { + const value = n.value; + const valueStr = formatValue(value, publishOptions); + if (isNaN(n.evol)) { + return valueStr; + } else { + const evolStr = n.evol.toLocaleString("fr-FR", { + useGrouping: false, + maximumFractionDigits: + publishOptions.evolMaxFractioDigits === undefined + ? 1 + : publishOptions.evolMaxFractioDigits, + signDisplay: "always", + }); + const evolPercentStr = Math.round(n.evolPercent).toLocaleString("fr-FR", { + useGrouping: false, + signDisplay: "always", + maximumFractionDigits: + publishOptions.evolPctMaxFractioDigits === undefined + ? 1 + : publishOptions.evolPctMaxFractioDigits, + }); + + return `${valueStr} (${evolStr} | ${evolPercentStr}%)`; + } +} diff --git a/src/notion/publish/publishPeriodStats.ts b/src/notion/publish/publishPeriodStats.ts index 8c5d41a..f747cac 100644 --- a/src/notion/publish/publishPeriodStats.ts +++ b/src/notion/publish/publishPeriodStats.ts @@ -1,17 +1,15 @@ import { Client, isFullPage } from "@notionhq/client"; import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints"; import { ELPeriodStats, ValueWithEvol } from "../../statistiques/ELStats"; +import { + StatPublishOptions, + statPropsPublishOptions, +} from "../statPropsPublishOptions"; import { titlePropertyToText } from "../utils/properties/titlePropertyToText"; import { queryAllDbResults } from "../utils/queryAllDbResults"; import { removeBlocks } from "../utils/removeBlocks"; import { CreatePageProperties } from "../utils/types/CreatePageProperties"; -import { - statNameDureeResistanceMediane, - statNameDureeResistanceMoyenne, - statsNameNbFamillesMisesEnDemeure, - statsNameNbFamillesResistantes, - statsNamePourcentageEntreeApresMisesEnDemeure, -} from "./statNames"; +import { formatValueWithEvol } from "./format/formatValueWithEvol"; export async function publishPeriodStats( notionClient: Client, @@ -58,59 +56,61 @@ export async function publishPeriodStats( // Create rows to create for (const periodId of periodIdsToCreate) { - const stat = indexedPeriodStats[periodId]; + const periodStats = indexedPeriodStats[periodId]; await notionClient.pages.create({ parent: { database_id: periodStatsDbId, }, - properties: buildRowPropertiesForUpsert(stat), + properties: buildRowPropertiesForUpsert(periodId, periodStats.stats), }); } // Update rows for (const periodId of periodIdsToUpdate) { - const stat = indexedPeriodStats[periodId]; + const periodStats = indexedPeriodStats[periodId]; const row = indexedPeriodRows[periodId]; await notionClient.pages.update({ page_id: row.id, - properties: buildRowPropertiesForUpsert(stat), + properties: buildRowPropertiesForUpsert(periodId, periodStats.stats), }); } } function buildRowPropertiesForUpsert( - stat: ELPeriodStats + periodId: string, + stats: ELPeriodStats["stats"] ): CreatePageProperties { + const statsNotionProps: CreatePageProperties = Object.fromEntries( + (Object.keys(stats) as Array).map( + (jsProp) => { + const value: ValueWithEvol = stats[jsProp]; + const publishOptions = statPropsPublishOptions[jsProp]; + return [ + publishOptions.notionPropName, + valueWithEvolProp(value, publishOptions), + ]; + } + ) + ); return { Période: { title: [ { text: { - content: stat.periodId, + content: periodId, }, }, ], }, - [statsNameNbFamillesResistantes]: valueWithEvolProp( - stat.nbFamilleResistantes - ), - [statNameDureeResistanceMediane]: valueWithEvolProp( - stat.dureeResistanceMediane - ), - [statNameDureeResistanceMoyenne]: valueWithEvolProp( - stat.dureeResistanceMoyenne - ), - [statsNameNbFamillesMisesEnDemeure]: valueWithEvolProp( - stat.nbFamillesMisesEnDemeure - ), - [statsNamePourcentageEntreeApresMisesEnDemeure]: valueWithEvolProp( - stat.pourcentageEntreeApresMiseEnDemeure - ), + ...statsNotionProps, }; } -function valueWithEvolProp(n: ValueWithEvol) { - const formatted = formatValueWithEvol(n); +function valueWithEvolProp( + n: ValueWithEvol, + publishOptions: StatPublishOptions +) { + const formatted = formatValueWithEvol(n, publishOptions); return { rich_text: [ { @@ -121,24 +121,3 @@ function valueWithEvolProp(n: ValueWithEvol) { ], }; } -function formatValueWithEvol(n: ValueWithEvol): string { - const value = n.value.toLocaleString("fr-FR", { - useGrouping: false, - maximumFractionDigits: 2, - }); - if (isNaN(n.evol)) { - return value; - } else { - const evol = n.evol.toLocaleString("fr-FR", { - useGrouping: false, - maximumFractionDigits: 2, - signDisplay: "always", - }); - const evolPercent = Math.round(n.evolPercent).toLocaleString("fr-FR", { - useGrouping: false, - signDisplay: "always", - }); - - return `${value} (${evol} | ${evolPercent}%)`; - } -} diff --git a/src/notion/publish/publishStatsActuelles.ts b/src/notion/publish/publishStatsActuelles.ts index 825f517..2111de8 100644 --- a/src/notion/publish/publishStatsActuelles.ts +++ b/src/notion/publish/publishStatsActuelles.ts @@ -1,23 +1,53 @@ import { Client, isFullBlock } from "@notionhq/client"; import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints"; import { ELStatsActuelles } from "../../statistiques/ELStats"; +import { + StatPublishOptions, + statPropsPublishOptions, +} from "../statPropsPublishOptions"; import { listAllChildrenBlocks } from "../utils/listAllChildrenBlocks"; import { removeBlocks } from "../utils/removeBlocks"; import { richTextToPlainText } from "../utils/text/richTextToPlainText"; +import { formatValue } from "./format/formatValue"; import { currentStatsHeading, statsPageId } from "./publishStatisticsToNotion"; -import { - statNameDureeResistanceMediane, - statNameDureeResistanceMoyenne, - statsNameNbFamillesMisesEnDemeure, - statsNameNbFamillesResistantes, - statsNameNbFamillesResistantesOuEx, - statsNamePourcentageEntreeApresMisesEnDemeure, - statsNamePourcentageFamilleMisesEnDemeure, -} from "./statNames"; export async function publishStatsActuelles( notionClient: Client, statsActuelles: ELStatsActuelles +) { + const newBlocks = ( + Object.keys(statsActuelles) as Array + ).map((jsProp) => { + const value: number = statsActuelles[jsProp]; + const publishOptions = statPropsPublishOptions[jsProp]; + return currentStatBlock(value, publishOptions); + }); + await updateStatsActuellesBlocks(notionClient, newBlocks); +} + +function currentStatBlock( + value: number, + publishOptions: StatPublishOptions +): BlockObjectRequest { + const formattedValue = formatValue(value, publishOptions); + + const content = `${publishOptions.notionPropName} : ${formattedValue}`; + return { + paragraph: { + rich_text: [ + { + text: { + content: content, + }, + }, + ], + }, + }; +} + +async function updateStatsActuellesBlocks( + notionClient: Client, + blocks: BlockObjectRequest[] ) { const childrenBlocks = ( await listAllChildrenBlocks(notionClient, { @@ -46,60 +76,9 @@ export async function publishStatsActuelles( .map((b) => b.id); await removeBlocks(notionClient, blocksIdsToRemove); - notionClient.blocks.children.append({ + await notionClient.blocks.children.append({ block_id: statsPageId, after: currentStatsHeadingBlock.id, - children: [ - currentStatBlock( - statsNameNbFamillesResistantes, - statsActuelles.nbFamilleResistantes - ), - currentStatBlock( - statsNameNbFamillesResistantesOuEx, - statsActuelles.nbFamilleResistantesOrEx - ), - currentStatBlock( - statNameDureeResistanceMoyenne, - statsActuelles.dureeResistanceMoyenne - ), - currentStatBlock( - statNameDureeResistanceMediane, - statsActuelles.dureeResistanceMediane - ), - currentStatBlock( - statsNameNbFamillesMisesEnDemeure, - statsActuelles.nbFamillesMiseEnDemeure - ), - currentStatBlock( - statsNamePourcentageFamilleMisesEnDemeure, - statsActuelles.pourcentageFamillesMisesEnDemeure - ), - currentStatBlock( - statsNamePourcentageEntreeApresMisesEnDemeure, - statsActuelles.pourcentageEntreeApresMiseEnDemeure - ), - ], + children: [...blocks], }); } - -function currentStatBlock( - stateName: string, - value: number -): BlockObjectRequest { - return { - paragraph: { - rich_text: [ - { - text: { - content: - stateName + - ": " + - value.toLocaleString("us-FR", { - maximumFractionDigits: 0, - }), - }, - }, - ], - }, - }; -} diff --git a/src/notion/publish/statNames.ts b/src/notion/publish/statNames.ts deleted file mode 100644 index 758aaf9..0000000 --- a/src/notion/publish/statNames.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const statNameDureeResistanceMoyenne = "Durée Résistance Moyenne"; -export const statNameDureeResistanceMediane = "Durée Résistance Médiane"; -export const statsNameNbFamillesResistantes = "Nb Familles Résistantes"; -export const statsNameNbFamillesResistantesOuEx = - "Nb Familles Résistante ou Ex-Résistantes"; -export const statsNameNbFamillesMisesEnDemeure = "Nb Familles Mises en Demeure"; -export const statsNamePourcentageFamilleMisesEnDemeure = - "Pourcentage de Familles Mises en Demeure"; -export const statsNamePourcentageEntreeApresMisesEnDemeure = - "Pourcentage d'Entrees Après Mises en Demeure"; diff --git a/src/notion/statPropsPublishOptions.ts b/src/notion/statPropsPublishOptions.ts new file mode 100644 index 0000000..69f51b4 --- /dev/null +++ b/src/notion/statPropsPublishOptions.ts @@ -0,0 +1,41 @@ +import { ELPeriodStats, ELStatsActuelles } from "../statistiques/ELStats"; + +export const statPropsPublishOptions: { + [jsPropName in statsPropNames]: StatPublishOptions; +} = { + nbFamilleResistantes: { + notionPropName: "Nb Familles Résistantes", + }, + dureeResistanceMoyenne: { + notionPropName: "Durée Résistance Moyenne", + unit: "j", + }, + dureeResistanceMediane: { + notionPropName: "Durée Résistance Médiane", + unit: "j", + }, + nbFamilleResistantesOrEx: { + notionPropName: "Nb Familles Résistante ou Ex-Résistantes", + }, + nbFamillesMisesEnDemeure: { + notionPropName: "Nb Familles Mises en Demeure", + }, + pourcentageFamillesMisesEnDemeure: { + notionPropName: "Pourcentage de Familles Mises en Demeure", + unit: "%", + }, + pourcentageEntreeApresMiseEnDemeure: { + notionPropName: "Pourcentage d'Entrees Après Mises en Demeure", + unit: "%", + }, +}; +export type statsPropNames = + | keyof ELPeriodStats["stats"] + | keyof ELStatsActuelles; +export type StatPublishOptions = { + notionPropName: string; + unit?: string; + valueMaxFractioDigits?: number; + evolMaxFractioDigits?: number; + evolPctMaxFractioDigits?: number; +}; diff --git a/src/statistiques/ELStats.ts b/src/statistiques/ELStats.ts index fb51346..65dbc49 100644 --- a/src/statistiques/ELStats.ts +++ b/src/statistiques/ELStats.ts @@ -8,21 +8,22 @@ export type ELStatsActuelles = { nbFamilleResistantes: number; /** Includes Ancient resistants */ nbFamilleResistantesOrEx: number; - dureeResistanceMoyenne: number; dureeResistanceMediane: number; - nbFamillesMiseEnDemeure: number; + nbFamillesMisesEnDemeure: number; pourcentageFamillesMisesEnDemeure: number; pourcentageEntreeApresMiseEnDemeure: number; }; export type ELPeriodStats = { periodId: string; - nbFamilleResistantes: ValueWithEvol; - dureeResistanceMoyenne: ValueWithEvol; - dureeResistanceMediane: ValueWithEvol; - nbFamillesMisesEnDemeure: ValueWithEvol; - pourcentageEntreeApresMiseEnDemeure: ValueWithEvol; + stats: { + nbFamilleResistantes: ValueWithEvol; + dureeResistanceMoyenne: ValueWithEvol; + dureeResistanceMediane: ValueWithEvol; + nbFamillesMisesEnDemeure: ValueWithEvol; + pourcentageEntreeApresMiseEnDemeure: ValueWithEvol; + }; }; export type ValueWithEvol = { diff --git a/src/statistiques/computeELPeriodStats.ts b/src/statistiques/computeELPeriodStats.ts index 142342e..17deb90 100644 --- a/src/statistiques/computeELPeriodStats.ts +++ b/src/statistiques/computeELPeriodStats.ts @@ -15,7 +15,7 @@ export function computeELPeriodStats( periods: IdentifiedPeriod[] ): ELPeriodStats[] { const periodStats: ELPeriodStats[] = []; - let previousELPeriodStats: ELPeriodStats | null = null; + let previousELPeriodStats: ELPeriodStats["stats"] | null = null; for (const period of periods) { const periodEndOrNow = period.end.getTime() > Date.now() ? new Date(Date.now()) : period.end; @@ -53,29 +53,31 @@ export function computeELPeriodStats( const stats: ELPeriodStats = { periodId: period.id, - nbFamilleResistantes: valueWithEvol( - nbFamilleResistantes, - previousELPeriodStats?.nbFamilleResistantes.value - ), - dureeResistanceMediane: valueWithEvol( - dureeResistanceMediane, - previousELPeriodStats?.dureeResistanceMediane.value - ), - dureeResistanceMoyenne: valueWithEvol( - dureeResistanceMoyenne, - previousELPeriodStats?.dureeResistanceMoyenne.value - ), - nbFamillesMisesEnDemeure: valueWithEvol( - nbFamillesMiseEnDemeure, - previousELPeriodStats?.nbFamillesMisesEnDemeure.value - ), - pourcentageEntreeApresMiseEnDemeure: valueWithEvol( - pourcentageEntreeApresMiseEnDemeure, - previousELPeriodStats?.pourcentageEntreeApresMiseEnDemeure.value - ), + stats: { + nbFamilleResistantes: valueWithEvol( + nbFamilleResistantes, + previousELPeriodStats?.nbFamilleResistantes.value + ), + dureeResistanceMediane: valueWithEvol( + dureeResistanceMediane, + previousELPeriodStats?.dureeResistanceMediane.value + ), + dureeResistanceMoyenne: valueWithEvol( + dureeResistanceMoyenne, + previousELPeriodStats?.dureeResistanceMoyenne.value + ), + nbFamillesMisesEnDemeure: valueWithEvol( + nbFamillesMiseEnDemeure, + previousELPeriodStats?.nbFamillesMisesEnDemeure.value + ), + pourcentageEntreeApresMiseEnDemeure: valueWithEvol( + pourcentageEntreeApresMiseEnDemeure, + previousELPeriodStats?.pourcentageEntreeApresMiseEnDemeure.value + ), + }, }; periodStats.push(stats); - previousELPeriodStats = stats; + previousELPeriodStats = stats?.stats; } return periodStats; } diff --git a/src/statistiques/computeStatsActuelles.ts b/src/statistiques/computeStatsActuelles.ts index ab9d495..0db935a 100644 --- a/src/statistiques/computeStatsActuelles.ts +++ b/src/statistiques/computeStatsActuelles.ts @@ -35,7 +35,7 @@ export function computeStatsActuelles(familles: Famille[]): ELStatsActuelles { nbFamilleResistantesOrEx: resistantsOrEx.length, dureeResistanceMoyenne: dureeMoyenne, dureeResistanceMediane: dureeMediane, - nbFamillesMiseEnDemeure: familleAvecMiseEnDemeure.length, + nbFamillesMisesEnDemeure: familleAvecMiseEnDemeure.length, pourcentageFamillesMisesEnDemeure: (100 * familleAvecMiseEnDemeure.length) / resistantsOrEx.length, pourcentageEntreeApresMiseEnDemeure: