feat: introduce Teams & OKRs feature with models, types, and UI components for team management and objective tracking
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 12m53s

This commit is contained in:
Julien Froidefond
2026-01-07 10:11:59 +01:00
parent e3a47dd7e5
commit 5f661c8bfd
35 changed files with 3993 additions and 0 deletions

View File

@@ -415,3 +415,159 @@ export const YEAR_REVIEW_BY_CATEGORY: Record<
},
{} as Record<YearReviewCategory, YearReviewSectionConfig>
);
// ============================================
// Teams & OKRs - Type Definitions
// ============================================
export type TeamRole = 'ADMIN' | 'MEMBER';
export type OKRStatus = 'NOT_STARTED' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED';
export type KeyResultStatus = 'NOT_STARTED' | 'IN_PROGRESS' | 'COMPLETED' | 'AT_RISK';
export interface Team {
id: string;
name: string;
description: string | null;
createdById: string;
members: TeamMember[];
createdAt: Date;
updatedAt: Date;
}
export interface TeamMember {
id: string;
teamId: string;
userId: string;
user: User;
role: TeamRole;
okrs: OKR[];
joinedAt: Date;
}
export interface OKR {
id: string;
teamMemberId: string;
objective: string;
description: string | null;
period: string;
startDate: Date;
endDate: Date;
status: OKRStatus;
keyResults: KeyResult[];
progress?: number; // Calculé
createdAt: Date;
updatedAt: Date;
}
export interface KeyResult {
id: string;
okrId: string;
title: string;
targetValue: number;
currentValue: number;
unit: string;
status: KeyResultStatus;
order: number;
notes: string | null;
createdAt: Date;
updatedAt: Date;
}
// ============================================
// Teams & OKRs - Input Types
// ============================================
export interface CreateTeamInput {
name: string;
description?: string;
}
export interface UpdateTeamInput {
name?: string;
description?: string;
}
export interface AddTeamMemberInput {
userId: string;
role?: TeamRole;
}
export interface UpdateMemberRoleInput {
role: TeamRole;
}
export interface CreateOKRInput {
teamMemberId: string;
objective: string;
description?: string;
period: string;
startDate: Date;
endDate: Date;
keyResults: CreateKeyResultInput[];
}
export interface UpdateOKRInput {
objective?: string;
description?: string;
period?: string;
startDate?: Date;
endDate?: Date;
status?: OKRStatus;
}
export interface CreateKeyResultInput {
title: string;
targetValue: number;
unit?: string;
order?: number;
}
export interface UpdateKeyResultInput {
currentValue?: number;
status?: KeyResultStatus;
notes?: string;
}
// ============================================
// Teams & OKRs - UI Config
// ============================================
export const OKR_STATUS_LABELS: Record<OKRStatus, string> = {
NOT_STARTED: 'Non démarré',
IN_PROGRESS: 'En cours',
COMPLETED: 'Terminé',
CANCELLED: 'Annulé',
};
export const KEY_RESULT_STATUS_LABELS: Record<KeyResultStatus, string> = {
NOT_STARTED: 'Non démarré',
IN_PROGRESS: 'En cours',
COMPLETED: 'Terminé',
AT_RISK: 'À risque',
};
export const TEAM_ROLE_LABELS: Record<TeamRole, string> = {
ADMIN: 'Admin',
MEMBER: 'Membre',
};
// Génère les périodes par défaut : trimestres de l'année en cours + trimestres de l'année suivante
function generatePeriodSuggestions(): string[] {
const currentYear = new Date().getFullYear();
const nextYear = currentYear + 1;
const periods: string[] = [];
// Trimestres de l'année en cours
for (let q = 1; q <= 4; q++) {
periods.push(`Q${q} ${currentYear}`);
}
// Trimestres de l'année suivante
for (let q = 1; q <= 4; q++) {
periods.push(`Q${q} ${nextYear}`);
}
return periods;
}
export const PERIOD_SUGGESTIONS = generatePeriodSuggestions();