feate: ajoute options de formattage des stas

wip-related-pages
sebastien.arod@gmail.com 2024-06-04 10:50:16 +02:00
parent e1acd45eb7
commit 39d1125681
10 changed files with 225 additions and 153 deletions

View File

@ -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%");
});
});

View File

@ -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;
}

View File

@ -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}%)`;
}
}

View File

@ -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<keyof ELPeriodStats["stats"]>).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}%)`;
}
}

View File

@ -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<keyof ELStatsActuelles>
).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,
}),
},
},
],
},
};
}

View File

@ -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";

View File

@ -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;
};

View File

@ -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 = {

View File

@ -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;
}

View File

@ -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: