refactor: rule of coverage are in one place
This commit is contained in:
@@ -7,7 +7,12 @@ import {
|
||||
TeamMember,
|
||||
TeamMemberSkill,
|
||||
} from "@/lib/team-review-types";
|
||||
import { SkillLevel } from "@/lib/types";
|
||||
import { SkillLevel, SKILL_LEVEL_VALUES } from "@/lib/types";
|
||||
import {
|
||||
COVERAGE_OBJECTIVES,
|
||||
isCoverageBelowObjective,
|
||||
calculateSkillCoverage,
|
||||
} from "@/lib/evaluation-utils";
|
||||
|
||||
export class TeamReviewService {
|
||||
static async getTeamReviewData(teamId: string): Promise<TeamReviewData> {
|
||||
@@ -100,7 +105,11 @@ export class TeamReviewService {
|
||||
skillName: row.skill_name,
|
||||
category: row.category,
|
||||
importance: row.importance || "standard",
|
||||
level: row.level as SkillLevel,
|
||||
level: row.level as
|
||||
| "never"
|
||||
| "not-autonomous"
|
||||
| "autonomous"
|
||||
| "expert",
|
||||
canMentor: row.can_mentor || false,
|
||||
wantsToLearn: row.wants_to_learn || false,
|
||||
};
|
||||
@@ -140,8 +149,14 @@ export class TeamReviewService {
|
||||
const teamMembers = evaluations.filter((e) => e.level).length;
|
||||
|
||||
const totalTeamMembers = membersMap.size;
|
||||
const coverage =
|
||||
totalTeamMembers > 0 ? (teamMembers / totalTeamMembers) * 100 : 0;
|
||||
|
||||
// Calculer la couverture en fonction des niveaux
|
||||
const levels = evaluations.map((e) =>
|
||||
e.level
|
||||
? SKILL_LEVEL_VALUES[e.level as keyof typeof SKILL_LEVEL_VALUES]
|
||||
: 0
|
||||
);
|
||||
const coverage = calculateSkillCoverage(levels, totalTeamMembers);
|
||||
|
||||
// Déterminer le niveau de risque en fonction de l'importance
|
||||
const risk =
|
||||
@@ -159,7 +174,7 @@ export class TeamReviewService {
|
||||
category: skill.category,
|
||||
icon: skill.icon,
|
||||
importance: skill.importance || "standard",
|
||||
team_members: teamMembers,
|
||||
teamMembers,
|
||||
experts,
|
||||
mentors,
|
||||
learners,
|
||||
@@ -175,8 +190,8 @@ export class TeamReviewService {
|
||||
if (!categoriesMap.has(skill.category)) {
|
||||
categoriesMap.set(skill.category, {
|
||||
category: skill.category,
|
||||
total_skills: 0,
|
||||
covered_skills: 0,
|
||||
totalSkills: 0,
|
||||
coveredSkills: 0,
|
||||
experts: 0,
|
||||
mentors: 0,
|
||||
learners: 0,
|
||||
@@ -189,13 +204,13 @@ export class TeamReviewService {
|
||||
}
|
||||
|
||||
const categoryStats = categoriesMap.get(skill.category)!;
|
||||
categoryStats.total_skills++;
|
||||
categoryStats.totalSkills++;
|
||||
|
||||
const skillGap = skillGaps.find(
|
||||
(gap) => gap.skillId === skill.skill_id
|
||||
);
|
||||
if (skillGap) {
|
||||
if (skillGap.team_members > 0) categoryStats.covered_skills++;
|
||||
if (skillGap.teamMembers > 0) categoryStats.coveredSkills++;
|
||||
categoryStats.experts += skillGap.experts;
|
||||
categoryStats.mentors += skillGap.mentors;
|
||||
categoryStats.learners += skillGap.learners;
|
||||
@@ -203,11 +218,14 @@ export class TeamReviewService {
|
||||
// Calculer la couverture des compétences critiques
|
||||
if (
|
||||
skillGap.importance === "incontournable" &&
|
||||
skillGap.coverage > 50
|
||||
!isCoverageBelowObjective(skillGap.coverage, skillGap.importance)
|
||||
) {
|
||||
categoryStats.criticalSkillsCoverage.incontournable++;
|
||||
}
|
||||
if (skillGap.importance === "majeure" && skillGap.coverage > 50) {
|
||||
if (
|
||||
skillGap.importance === "majeure" &&
|
||||
!isCoverageBelowObjective(skillGap.coverage, skillGap.importance)
|
||||
) {
|
||||
categoryStats.criticalSkillsCoverage.majeure++;
|
||||
}
|
||||
}
|
||||
@@ -219,8 +237,8 @@ export class TeamReviewService {
|
||||
).map((category) => ({
|
||||
...category,
|
||||
coverage:
|
||||
category.total_skills > 0
|
||||
? (category.covered_skills / category.total_skills) * 100
|
||||
category.totalSkills > 0
|
||||
? (category.coveredSkills / category.totalSkills) * 100
|
||||
: 0,
|
||||
}));
|
||||
|
||||
@@ -236,7 +254,14 @@ export class TeamReviewService {
|
||||
incontournable:
|
||||
(skillGaps
|
||||
.filter((gap) => gap.importance === "incontournable")
|
||||
.reduce((acc, gap) => acc + (gap.coverage > 50 ? 1 : 0), 0) /
|
||||
.reduce(
|
||||
(acc, gap) =>
|
||||
acc +
|
||||
(!isCoverageBelowObjective(gap.coverage, gap.importance)
|
||||
? 1
|
||||
: 0),
|
||||
0
|
||||
) /
|
||||
Math.max(
|
||||
1,
|
||||
skillGaps.filter((gap) => gap.importance === "incontournable")
|
||||
@@ -246,7 +271,14 @@ export class TeamReviewService {
|
||||
majeure:
|
||||
(skillGaps
|
||||
.filter((gap) => gap.importance === "majeure")
|
||||
.reduce((acc, gap) => acc + (gap.coverage > 50 ? 1 : 0), 0) /
|
||||
.reduce(
|
||||
(acc, gap) =>
|
||||
acc +
|
||||
(!isCoverageBelowObjective(gap.coverage, gap.importance)
|
||||
? 1
|
||||
: 0),
|
||||
0
|
||||
) /
|
||||
Math.max(
|
||||
1,
|
||||
skillGaps.filter((gap) => gap.importance === "majeure").length
|
||||
@@ -298,7 +330,9 @@ export class TeamReviewService {
|
||||
|
||||
// Analyser les gaps critiques par importance
|
||||
const uncoveredIncontournables = skillGaps.filter(
|
||||
(gap) => gap.importance === "incontournable" && gap.coverage < 50
|
||||
(gap) =>
|
||||
gap.importance === "incontournable" &&
|
||||
isCoverageBelowObjective(gap.coverage, gap.importance)
|
||||
);
|
||||
if (uncoveredIncontournables.length > 0) {
|
||||
recommendations.push(
|
||||
@@ -311,7 +345,9 @@ export class TeamReviewService {
|
||||
}
|
||||
|
||||
const uncoveredMajeures = skillGaps.filter(
|
||||
(gap) => gap.importance === "majeure" && gap.coverage < 30
|
||||
(gap) =>
|
||||
gap.importance === "majeure" &&
|
||||
isCoverageBelowObjective(gap.coverage, gap.importance)
|
||||
);
|
||||
if (uncoveredMajeures.length > 0) {
|
||||
recommendations.push(
|
||||
@@ -338,7 +374,7 @@ export class TeamReviewService {
|
||||
|
||||
// Analyser la couverture des catégories
|
||||
const lowCoverageCategories = categoryCoverage
|
||||
.filter((cat) => cat.coverage < 50)
|
||||
.filter((cat) => cat.coverage < COVERAGE_OBJECTIVES.majeure)
|
||||
.map((cat) => cat.category);
|
||||
if (lowCoverageCategories.length > 0) {
|
||||
recommendations.push(
|
||||
|
||||
Reference in New Issue
Block a user