mirror of
https://framagit.org/enfance-libre/statistiques
synced 2025-12-07 23:23:44 +00:00
feat: ajoute dureeMoyenneResistance dureeMedianeResistance
This commit is contained in:
parent
74b7fa8f0e
commit
962bdcde80
15 changed files with 218 additions and 110 deletions
|
|
@ -1,7 +1,25 @@
|
||||||
import { arePeriodsOverlaping } from "../period/arePeriodsOverlaping";
|
import { arePeriodsOverlaping } from "../period/arePeriodsOverlaping";
|
||||||
import { Period } from "../period/Period";
|
import { Period } from "../period/Period";
|
||||||
|
|
||||||
export type FamilyStatus =
|
export type Family = {
|
||||||
|
notionId: string;
|
||||||
|
Titre: string;
|
||||||
|
Statut: StatutFamille;
|
||||||
|
Integration: Date | null;
|
||||||
|
Sortie: Date | null;
|
||||||
|
Evenements: FamilyEvent[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FamilyEvent = {
|
||||||
|
notionId: string;
|
||||||
|
notionIdFamille: string;
|
||||||
|
Évènement: string;
|
||||||
|
Date: Date | null;
|
||||||
|
Type: string;
|
||||||
|
"Enfants concernés": string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StatutFamille =
|
||||||
| "Résistant.e"
|
| "Résistant.e"
|
||||||
| "Ex résistant·e·s"
|
| "Ex résistant·e·s"
|
||||||
| "À préciser"
|
| "À préciser"
|
||||||
|
|
@ -11,43 +29,31 @@ export type FamilyStatus =
|
||||||
| "Déclaration Validée - Attente éléments"
|
| "Déclaration Validée - Attente éléments"
|
||||||
| "Abdandon"
|
| "Abdandon"
|
||||||
| "Incompatible";
|
| "Incompatible";
|
||||||
export type Family = {
|
|
||||||
notionId: string;
|
|
||||||
title: string;
|
|
||||||
status: FamilyStatus;
|
|
||||||
|
|
||||||
startResistsant: Date | null;
|
|
||||||
endResistant: Date | null;
|
|
||||||
evenements: FamilyEvent[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export function isResistant(family: Family): boolean {
|
export function isResistant(family: Family): boolean {
|
||||||
return (
|
return (
|
||||||
family.status === "Résistant.e" &&
|
family.Statut === "Résistant.e" &&
|
||||||
family.startResistsant !== null &&
|
family.Integration !== null &&
|
||||||
family.endResistant === null
|
family.Sortie === null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isExResistant(family: Family): boolean {
|
export function isExResistant(family: Family): boolean {
|
||||||
return (
|
return (
|
||||||
family.status === "Ex résistant·e·s" &&
|
family.Statut === "Ex résistant·e·s" &&
|
||||||
family.startResistsant !== null &&
|
family.Integration !== null &&
|
||||||
family.endResistant !== null
|
family.Sortie !== null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isResistantAtDate(family: Family, date: Date): boolean {
|
export function isResistantAtDate(family: Family, date: Date): boolean {
|
||||||
if (
|
if (isResistant(family) && family.Integration!.getTime() <= date.getTime()) {
|
||||||
isResistant(family) &&
|
|
||||||
family.startResistsant!.getTime() <= date.getTime()
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
isExResistant(family) &&
|
isExResistant(family) &&
|
||||||
family.startResistsant!.getTime() <= date.getTime() &&
|
family.Integration!.getTime() <= date.getTime() &&
|
||||||
family.endResistant!.getTime() > date.getTime()
|
family.Sortie!.getTime() > date.getTime()
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -62,25 +68,20 @@ export function isResistantOverPeriod(family: Family, period: Period): boolean {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function periodOfResistance(family: Family): Period | null {
|
export function periodOfResistance(family: Family): Period | null {
|
||||||
if (isResistant(family)) {
|
if (isResistant(family)) {
|
||||||
const periodResistant: Period = {
|
const periodResistant: Period = {
|
||||||
start: family.startResistsant!,
|
start: family.Integration!,
|
||||||
end: new Date(Date.now()),
|
end: new Date(Date.now()),
|
||||||
};
|
};
|
||||||
return periodResistant;
|
return periodResistant;
|
||||||
}
|
}
|
||||||
if (isExResistant(family)) {
|
if (isExResistant(family)) {
|
||||||
const periodResistant: Period = {
|
const periodResistant: Period = {
|
||||||
start: family.startResistsant!,
|
start: family.Integration!,
|
||||||
end: family.endResistant!,
|
end: family.Sortie!,
|
||||||
};
|
};
|
||||||
return periodResistant;
|
return periodResistant;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FamilyEvent = {
|
|
||||||
date: Date;
|
|
||||||
type: string;
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -13,49 +13,49 @@ export type ConsistencyIssue = {
|
||||||
function checkFamilyDataConsistency(family: Family) {
|
function checkFamilyDataConsistency(family: Family) {
|
||||||
const consistencyIssues: ConsistencyIssue[] = [];
|
const consistencyIssues: ConsistencyIssue[] = [];
|
||||||
|
|
||||||
if (family.status === "Résistant.e") {
|
if (family.Statut === "Résistant.e") {
|
||||||
if (family.startResistsant === null) {
|
if (family.Integration === null) {
|
||||||
consistencyIssues.push({
|
consistencyIssues.push({
|
||||||
familyId: family.title,
|
familyId: family.Titre,
|
||||||
issueType: "Résistant.e without startResistant",
|
issueType: "Résistant.e without startResistant",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (family.endResistant !== null) {
|
if (family.Sortie !== null) {
|
||||||
consistencyIssues.push({
|
consistencyIssues.push({
|
||||||
familyId: family.title,
|
familyId: family.Titre,
|
||||||
issueType: "Résistant.e with endResistant!!",
|
issueType: "Résistant.e with endResistant!!",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (family.status === "Ex résistant·e·s") {
|
} else if (family.Statut === "Ex résistant·e·s") {
|
||||||
if (family.startResistsant === null) {
|
if (family.Integration === null) {
|
||||||
consistencyIssues.push({
|
consistencyIssues.push({
|
||||||
familyId: family.title,
|
familyId: family.Titre,
|
||||||
issueType: "Ex résistant.e.s without startResistant",
|
issueType: "Ex résistant.e.s without startResistant",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (family.endResistant === null) {
|
if (family.Sortie === null) {
|
||||||
consistencyIssues.push({
|
consistencyIssues.push({
|
||||||
familyId: family.title,
|
familyId: family.Titre,
|
||||||
issueType: "Ex résistant.e.s without endResistant",
|
issueType: "Ex résistant.e.s without endResistant",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (family.startResistsant!.getTime() > family.endResistant!.getTime()) {
|
if (family.Integration!.getTime() > family.Sortie!.getTime()) {
|
||||||
consistencyIssues.push({
|
consistencyIssues.push({
|
||||||
familyId: family.title,
|
familyId: family.Titre,
|
||||||
issueType: "startResistsant > endResistant ",
|
issueType: "startResistsant > endResistant ",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (family.startResistsant !== null) {
|
if (family.Integration !== null) {
|
||||||
consistencyIssues.push({
|
consistencyIssues.push({
|
||||||
familyId: family.title,
|
familyId: family.Titre,
|
||||||
issueType: family.status + " with startResistant",
|
issueType: family.Statut + " with startResistant",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (family.endResistant !== null) {
|
if (family.Sortie !== null) {
|
||||||
consistencyIssues.push({
|
consistencyIssues.push({
|
||||||
familyId: family.title,
|
familyId: family.Titre,
|
||||||
issueType: family.status + " with endResistant",
|
issueType: family.Statut + " with endResistant",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,73 @@
|
||||||
import { Client } from "@notionhq/client";
|
import { Client, isFullPage } from "@notionhq/client";
|
||||||
import {
|
import { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
|
||||||
PageObjectResponse,
|
import { Family, FamilyEvent, StatutFamille } from "../../data/Family";
|
||||||
QueryDatabaseParameters,
|
|
||||||
} from "@notionhq/client/build/src/api-endpoints";
|
|
||||||
import { Family, FamilyStatus } from "../../data/Family";
|
|
||||||
import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
|
import { datePropertyToDate } from "../utils/properties/datePropertyToDate";
|
||||||
|
import { relationPropertyToPageId } from "../utils/properties/relationPropertyToPAgeId";
|
||||||
|
import { selectPropertyToText } from "../utils/properties/selectPropertyToText";
|
||||||
import { statusPropertyToText } from "../utils/properties/statusPropertyToText";
|
import { statusPropertyToText } from "../utils/properties/statusPropertyToText";
|
||||||
import { titlePropertyToText } from "../utils/properties/titlePropertyToText copy";
|
import { titlePropertyToText } from "../utils/properties/titlePropertyToText";
|
||||||
import { queryAllDbResults } from "../utils/queryAllDbResults";
|
import { queryAllDbResults } from "../utils/queryAllDbResults";
|
||||||
import { assertFullPage } from "../utils/types/assertFullPage";
|
import { richTextPropertyToPlainText } from "../utils/text/richTextPropertyToPlainText";
|
||||||
|
|
||||||
export async function fetchFamiliesWithEventsFromNotion(
|
export async function fetchFamiliesWithEventsFromNotion(
|
||||||
notionClient: Client
|
notionClient: Client
|
||||||
): Promise<Family[]> {
|
): Promise<Family[]> {
|
||||||
const familiesDbId: string = "5b69e02b296d4a578f8c8ab7fe8b05da";
|
const familiesDbId: string = "5b69e02b296d4a578f8c8ab7fe8b05da";
|
||||||
const dbQuery: QueryDatabaseParameters = {
|
const familEventsDbId: string = "c4d434b4603c4481a4d445618ecdf999";
|
||||||
database_id: familiesDbId,
|
|
||||||
/*filter: {
|
const eventPages = (
|
||||||
property: "Statut",
|
await queryAllDbResults(notionClient, {
|
||||||
status: {
|
database_id: familEventsDbId,
|
||||||
equals: "Résistant.e",
|
})
|
||||||
},
|
).filter(isFullPage);
|
||||||
},*/
|
const familyPages = (
|
||||||
};
|
await queryAllDbResults(notionClient, {
|
||||||
|
database_id: familiesDbId,
|
||||||
|
})
|
||||||
|
).filter(isFullPage);
|
||||||
|
|
||||||
|
const familyEvents = eventPages.map((pageObjectResponse) => {
|
||||||
|
return buildFamilyEvent(pageObjectResponse);
|
||||||
|
});
|
||||||
|
|
||||||
const results = await queryAllDbResults(notionClient, dbQuery);
|
|
||||||
const families: Family[] = await Promise.all(
|
const families: Family[] = await Promise.all(
|
||||||
results.map((pageObjectResponse) => {
|
familyPages.map((pageObjectResponse) => {
|
||||||
assertFullPage(pageObjectResponse);
|
return buildFamily(pageObjectResponse, familyEvents);
|
||||||
return buildFamily(pageObjectResponse);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return families;
|
return families;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildFamily(page: PageObjectResponse): Family {
|
function buildFamilyEvent(page: PageObjectResponse): FamilyEvent {
|
||||||
|
const pageProperties = page.properties;
|
||||||
|
|
||||||
|
const familyEvent: FamilyEvent = {
|
||||||
|
notionId: page.id,
|
||||||
|
Évènement: titlePropertyToText(pageProperties, "Évènement"),
|
||||||
|
Type: selectPropertyToText(pageProperties, "Type")!,
|
||||||
|
"Enfants concernés": richTextPropertyToPlainText(
|
||||||
|
pageProperties,
|
||||||
|
"Enfants concernés"
|
||||||
|
),
|
||||||
|
Date: datePropertyToDate(pageProperties, "Date"),
|
||||||
|
notionIdFamille: relationPropertyToPageId(pageProperties, "Famille")!,
|
||||||
|
};
|
||||||
|
return familyEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildFamily(
|
||||||
|
page: PageObjectResponse,
|
||||||
|
familyEvents: FamilyEvent[]
|
||||||
|
): Family {
|
||||||
const pageProperties = page.properties;
|
const pageProperties = page.properties;
|
||||||
|
|
||||||
// TODO Fetch Family Events
|
|
||||||
const family: Family = {
|
const family: Family = {
|
||||||
notionId: page.id,
|
notionId: page.id,
|
||||||
title: titlePropertyToText(pageProperties, ""),
|
Titre: titlePropertyToText(pageProperties, ""),
|
||||||
status: statusPropertyToText(pageProperties, "Statut") as FamilyStatus,
|
Statut: statusPropertyToText(pageProperties, "Statut") as StatutFamille,
|
||||||
startResistsant: datePropertyToDate(pageProperties, "Intégration"),
|
Integration: datePropertyToDate(pageProperties, "Intégration"),
|
||||||
endResistant: datePropertyToDate(pageProperties, "Sortie"),
|
Sortie: datePropertyToDate(pageProperties, "Sortie"),
|
||||||
evenements: [],
|
Evenements: familyEvents.filter((fe) => fe.notionIdFamille === page.id),
|
||||||
};
|
};
|
||||||
return family;
|
return family;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,18 @@ export async function publishCurrentStats(
|
||||||
block_id: statsPageId,
|
block_id: statsPageId,
|
||||||
after: currentStatsHeadingBlock.id,
|
after: currentStatsHeadingBlock.id,
|
||||||
children: [
|
children: [
|
||||||
currentStatBlock("Nb Famille Résistante", stats.resistantsCount),
|
currentStatBlock("Nb Famille Résistante", stats.nbFamilleResistantes),
|
||||||
currentStatBlock(
|
currentStatBlock(
|
||||||
"Nb Famille Résistante ou Ex-Résistante",
|
"Nb Famille Résistante ou Ex-Résistante",
|
||||||
stats.resistantsOrExCount
|
stats.nbFamilleResistantesOrEx
|
||||||
|
),
|
||||||
|
currentStatBlock(
|
||||||
|
"Durée Moyenne Résistance (jours)",
|
||||||
|
stats.dureeMoyenneResistance
|
||||||
|
),
|
||||||
|
currentStatBlock(
|
||||||
|
"Durée Médiane Résistance (jours)",
|
||||||
|
stats.dureeMedianeResistance
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ export async function publishStatisticsToNotion(
|
||||||
) {
|
) {
|
||||||
await publishCurrentStats(notionClient, stats);
|
await publishCurrentStats(notionClient, stats);
|
||||||
|
|
||||||
await publishPeriodStats(notionClient, yearStatsDb, stats.years);
|
await publishPeriodStats(notionClient, yearStatsDb, stats.annees);
|
||||||
|
|
||||||
await publishPeriodStats(notionClient, monthStatsDb, stats.months);
|
await publishPeriodStats(notionClient, monthStatsDb, stats.mois);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function publishPeriodStats(
|
async function publishPeriodStats(
|
||||||
|
|
@ -50,10 +50,12 @@ async function publishPeriodStats(
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"Nb Famille Résistante": numberProp(stat.resistantsCount),
|
"Nb Famille Résistante": numberProp(stat.nbFamilleResistantes),
|
||||||
"Nb Famille Résistante - Evol": numberProp(stat.resistantsCountEvol),
|
"Nb Famille Résistante - Evol": numberProp(
|
||||||
|
stat.nbFamilleResistantesEvol
|
||||||
|
),
|
||||||
"Nb Famille Résistante - Evol %": numberProp(
|
"Nb Famille Résistante - Evol %": numberProp(
|
||||||
stat.resistantsCountEvolPercent
|
stat.nbFamilleResistantesEvolPercent
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
18
src/notion/utils/properties/relationPropertyToPageId.ts
Normal file
18
src/notion/utils/properties/relationPropertyToPageId.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { PageProperties } from "../types/PageProperties";
|
||||||
|
import { extractPagePropertyValue } from "./extractPagePropertyValue";
|
||||||
|
|
||||||
|
export function relationPropertyToPageId(
|
||||||
|
pageProperties: PageProperties,
|
||||||
|
propName: string
|
||||||
|
): string | null {
|
||||||
|
const propValue = extractPagePropertyValue(pageProperties, propName);
|
||||||
|
if (propValue.type !== "relation") {
|
||||||
|
throw new Error(
|
||||||
|
`Property ${propName} was expected to have type "relation" but got "${propValue.type}".`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (propValue.relation.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return propValue.relation[0].id;
|
||||||
|
}
|
||||||
18
src/notion/utils/properties/selectPropertyToText.ts
Normal file
18
src/notion/utils/properties/selectPropertyToText.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { PageProperties } from "../types/PageProperties";
|
||||||
|
import { extractPagePropertyValue } from "./extractPagePropertyValue";
|
||||||
|
|
||||||
|
export function selectPropertyToText(
|
||||||
|
pageProperties: PageProperties,
|
||||||
|
propName: string
|
||||||
|
): string | null {
|
||||||
|
const propValue = extractPagePropertyValue(pageProperties, propName);
|
||||||
|
if (propValue.type !== "select") {
|
||||||
|
throw new Error(
|
||||||
|
`Property ${propName} was expected to have type "select" but got "${propValue.type}".`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (propValue.select === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return propValue.select!.name;
|
||||||
|
}
|
||||||
|
|
@ -4,12 +4,15 @@ import { extractPagePropertyValue } from "./extractPagePropertyValue";
|
||||||
export function statusPropertyToText(
|
export function statusPropertyToText(
|
||||||
pageProperties: PageProperties,
|
pageProperties: PageProperties,
|
||||||
propName: string
|
propName: string
|
||||||
): string {
|
): string | null {
|
||||||
const propValue = extractPagePropertyValue(pageProperties, propName);
|
const propValue = extractPagePropertyValue(pageProperties, propName);
|
||||||
if (propValue.type !== "status") {
|
if (propValue.type !== "status") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Property ${propName} was expected to have type "title" but got "${propValue.type}".`
|
`Property ${propName} was expected to have type "status" but got "${propValue.type}".`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (propValue.status === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return propValue.status!.name;
|
return propValue.status!.name;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
src/period/daysInPeriod.ts
Normal file
6
src/period/daysInPeriod.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { differenceInDays } from "date-fns";
|
||||||
|
import { Period } from "./Period";
|
||||||
|
|
||||||
|
export function daysInPeriod(period: Period): number {
|
||||||
|
return differenceInDays(period.end, period.start);
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
export type ELStats = {
|
export type ELStats = {
|
||||||
/** Current Resistants Count */
|
nbFamilleResistantes: number;
|
||||||
resistantsCount: number;
|
|
||||||
/** Includes Ancient resistants */
|
/** Includes Ancient resistants */
|
||||||
resistantsOrExCount: number;
|
nbFamilleResistantesOrEx: number;
|
||||||
|
|
||||||
/**
|
dureeMoyenneResistance: number;
|
||||||
* Resistant count per Year
|
dureeMedianeResistance: number;
|
||||||
* Family Partially resistant over a year are counted in.
|
|
||||||
*/
|
|
||||||
years: ELPeriodStats[];
|
|
||||||
|
|
||||||
months: ELPeriodStats[];
|
annees: ELPeriodStats[];
|
||||||
|
|
||||||
|
mois: ELPeriodStats[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ELPeriodStats = {
|
export type ELPeriodStats = {
|
||||||
periodId: string;
|
periodId: string;
|
||||||
resistantsCount: number;
|
nbFamilleResistantes: number;
|
||||||
resistantsCountEvol: number;
|
nbFamilleResistantesEvol: number;
|
||||||
resistantsCountEvolPercent: number;
|
nbFamilleResistantesEvolPercent: number;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,14 @@ export function computeELPeriodStats(
|
||||||
|
|
||||||
const stats: ELPeriodStats = {
|
const stats: ELPeriodStats = {
|
||||||
periodId: period.id,
|
periodId: period.id,
|
||||||
|
nbFamilleResistantes: resistantsCount,
|
||||||
|
nbFamilleResistantesEvol: evol(
|
||||||
resistantsCount,
|
resistantsCount,
|
||||||
resistantsCountEvol: evol(
|
previousELPeriodStats?.nbFamilleResistantes
|
||||||
resistantsCount,
|
|
||||||
previousELPeriodStats?.resistantsCount
|
|
||||||
),
|
),
|
||||||
resistantsCountEvolPercent: evolPercent(
|
nbFamilleResistantesEvolPercent: evolPercent(
|
||||||
resistantsCount,
|
resistantsCount,
|
||||||
previousELPeriodStats?.resistantsCount
|
previousELPeriodStats?.nbFamilleResistantes
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
periodStats.push(stats);
|
periodStats.push(stats);
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
import { Family, isExResistant, isResistant } from "../data/Family";
|
import {
|
||||||
|
Family,
|
||||||
|
isExResistant,
|
||||||
|
isResistant,
|
||||||
|
periodOfResistance,
|
||||||
|
} from "../data/Family";
|
||||||
|
import { daysInPeriod } from "../period/daysInPeriod";
|
||||||
import { ELStats } from "./ELStats";
|
import { ELStats } from "./ELStats";
|
||||||
import { computeELPeriodStats } from "./computeELPeriodStats";
|
import { computeELPeriodStats } from "./computeELPeriodStats";
|
||||||
import { generateELMonths } from "./generateELMonths";
|
import { generateELMonths } from "./generateELMonths";
|
||||||
import { generateELYears } from "./generateELYears";
|
import { generateELYears } from "./generateELYears";
|
||||||
|
import { average } from "./math/average";
|
||||||
|
import { median } from "./math/median";
|
||||||
|
|
||||||
export function computeELStats(families: Family[]): ELStats {
|
export function computeELStats(families: Family[]): ELStats {
|
||||||
const resistantsCount = families.filter(isResistant).length;
|
const resistantsCount = families.filter(isResistant).length;
|
||||||
const resistantsOrExCount = families.filter(
|
const resistantsOrEx = families.filter(
|
||||||
(f) => isResistant(f) || isExResistant(f)
|
(f) => isResistant(f) || isExResistant(f)
|
||||||
).length;
|
);
|
||||||
|
const durations = resistantsOrEx.map((f) =>
|
||||||
|
daysInPeriod(periodOfResistance(f)!)
|
||||||
|
);
|
||||||
|
const dureeMoyenne = average(durations);
|
||||||
|
const dureeMediane = median(durations);
|
||||||
|
|
||||||
const elYears = generateELYears();
|
const elYears = generateELYears();
|
||||||
const yearsStats = computeELPeriodStats(families, elYears);
|
const yearsStats = computeELPeriodStats(families, elYears);
|
||||||
|
|
@ -17,9 +30,11 @@ export function computeELStats(families: Family[]): ELStats {
|
||||||
const monthsStats = computeELPeriodStats(families, months);
|
const monthsStats = computeELPeriodStats(families, months);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
resistantsCount,
|
nbFamilleResistantes: resistantsCount,
|
||||||
resistantsOrExCount,
|
nbFamilleResistantesOrEx: resistantsOrEx.length,
|
||||||
years: yearsStats,
|
dureeMoyenneResistance: dureeMoyenne,
|
||||||
months: monthsStats,
|
dureeMedianeResistance: dureeMediane,
|
||||||
|
annees: yearsStats,
|
||||||
|
mois: monthsStats,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
src/statistiques/math/average.ts
Normal file
5
src/statistiques/math/average.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
export function average(values: number[]): number {
|
||||||
|
if (values.length === 0) return NaN;
|
||||||
|
|
||||||
|
return values.reduce((a, b) => a + b) / values.length;
|
||||||
|
}
|
||||||
11
src/statistiques/math/median.ts
Normal file
11
src/statistiques/math/median.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
export function median(values: number[]): number {
|
||||||
|
if (values.length === 0) return NaN;
|
||||||
|
|
||||||
|
const sorted = [...values].sort((a, b) => a - b);
|
||||||
|
|
||||||
|
const half = Math.floor(sorted.length / 2);
|
||||||
|
|
||||||
|
return sorted.length % 2
|
||||||
|
? sorted[half]
|
||||||
|
: (sorted[half - 1] + sorted[half]) / 2;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue