feat: refactor workshop management by centralizing workshop data and improving session navigation across components
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m0s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m0s
This commit is contained in:
185
src/lib/workshops.ts
Normal file
185
src/lib/workshops.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Single source of truth for workshop types and metadata.
|
||||
* Used by: Header, NewWorkshopDropdown, WorkshopTabs, sessions page.
|
||||
*/
|
||||
|
||||
export const WORKSHOP_TYPE_IDS = [
|
||||
'swot',
|
||||
'motivators',
|
||||
'year-review',
|
||||
'weekly-checkin',
|
||||
'weather',
|
||||
] as const;
|
||||
|
||||
export type WorkshopTypeId = (typeof WORKSHOP_TYPE_IDS)[number];
|
||||
|
||||
export type WorkshopTabType = WorkshopTypeId | 'all' | 'byPerson';
|
||||
|
||||
export const VALID_TAB_PARAMS: WorkshopTabType[] = [
|
||||
'all',
|
||||
...WORKSHOP_TYPE_IDS,
|
||||
'byPerson',
|
||||
];
|
||||
|
||||
export interface WorkshopConfig {
|
||||
id: WorkshopTypeId;
|
||||
icon: string;
|
||||
label: string;
|
||||
labelShort: string;
|
||||
cardLabel: string; // For home page cards (e.g. "Météo" vs "Météo d'équipe")
|
||||
description: string;
|
||||
path: string; // e.g. /sessions, /motivators
|
||||
newPath: string; // e.g. /sessions/new
|
||||
accentColor: string;
|
||||
hasParticipant: boolean; // false for weather
|
||||
participantLabel: string; // 'Collaborateur' | 'Participant' | ''
|
||||
/** Home page marketing content */
|
||||
home: {
|
||||
tagline: string;
|
||||
description: string;
|
||||
features: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export const WORKSHOPS: WorkshopConfig[] = [
|
||||
{
|
||||
id: 'swot',
|
||||
icon: '📊',
|
||||
label: 'Analyse SWOT',
|
||||
labelShort: 'SWOT',
|
||||
cardLabel: 'Analyse SWOT',
|
||||
description: 'Forces, faiblesses, opportunités',
|
||||
path: '/sessions',
|
||||
newPath: '/sessions/new',
|
||||
accentColor: '#06b6d4',
|
||||
hasParticipant: true,
|
||||
participantLabel: 'Collaborateur',
|
||||
home: {
|
||||
tagline: 'Analysez. Planifiez. Progressez.',
|
||||
description:
|
||||
"Cartographiez les forces et faiblesses de vos collaborateurs. Identifiez opportunités et menaces pour définir des actions concrètes.",
|
||||
features: [
|
||||
'Matrice interactive Forces/Faiblesses/Opportunités/Menaces',
|
||||
'Actions croisées et plan de développement',
|
||||
'Collaboration en temps réel',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'motivators',
|
||||
icon: '🎯',
|
||||
label: 'Moving Motivators',
|
||||
labelShort: 'Motivators',
|
||||
cardLabel: 'Moving Motivators',
|
||||
description: 'Motivations intrinsèques',
|
||||
path: '/motivators',
|
||||
newPath: '/motivators/new',
|
||||
accentColor: '#8b5cf6',
|
||||
hasParticipant: true,
|
||||
participantLabel: 'Participant',
|
||||
home: {
|
||||
tagline: 'Révélez ce qui motive vraiment',
|
||||
description:
|
||||
"Explorez les 10 motivations intrinsèques de vos collaborateurs. Comprenez leur impact et alignez aspirations et missions.",
|
||||
features: [
|
||||
'10 cartes de motivation à classer',
|
||||
"Évaluation de l'influence positive/négative",
|
||||
'Récapitulatif personnalisé des motivations',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'year-review',
|
||||
icon: '📅',
|
||||
label: 'Year Review',
|
||||
labelShort: 'Year Review',
|
||||
cardLabel: 'Year Review',
|
||||
description: "Bilan de l'année",
|
||||
path: '/year-review',
|
||||
newPath: '/year-review/new',
|
||||
accentColor: '#f59e0b',
|
||||
hasParticipant: true,
|
||||
participantLabel: 'Participant',
|
||||
home: {
|
||||
tagline: "Faites le bilan de l'année",
|
||||
description:
|
||||
"Réalisez un bilan complet de l'année écoulée. Identifiez réalisations, défis, apprentissages et définissez vos objectifs pour l'année à venir.",
|
||||
features: [
|
||||
"5 catégories : Réalisations, Défis, Apprentissages, Objectifs, Moments",
|
||||
'Organisation par drag & drop',
|
||||
"Vue d'ensemble de l'année",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'weekly-checkin',
|
||||
icon: '📝',
|
||||
label: 'Weekly Check-in',
|
||||
labelShort: 'Check-in',
|
||||
cardLabel: 'Weekly Check-in',
|
||||
description: 'Suivi hebdomadaire',
|
||||
path: '/weekly-checkin',
|
||||
newPath: '/weekly-checkin/new',
|
||||
accentColor: '#10b981',
|
||||
hasParticipant: true,
|
||||
participantLabel: 'Participant',
|
||||
home: {
|
||||
tagline: 'Le point hebdomadaire avec vos collaborateurs',
|
||||
description:
|
||||
"Chaque semaine, faites le point avec vos collaborateurs sur ce qui s'est bien passé, ce qui s'est mal passé, les enjeux du moment et les prochains enjeux.",
|
||||
features: [
|
||||
"4 catégories : Bien passé, Mal passé, Enjeux du moment, Prochains enjeux",
|
||||
"Ajout d'émotions à chaque item (fierté, joie, frustration, etc.)",
|
||||
'Suivi hebdomadaire régulier',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'weather',
|
||||
icon: '🌤️',
|
||||
label: "Météo d'équipe",
|
||||
labelShort: 'Météo',
|
||||
cardLabel: 'Météo',
|
||||
description: 'Humeur et énergie',
|
||||
path: '/weather',
|
||||
newPath: '/weather/new',
|
||||
accentColor: '#3b82f6',
|
||||
hasParticipant: false,
|
||||
participantLabel: '',
|
||||
home: {
|
||||
tagline: "Votre état en un coup d'œil",
|
||||
description:
|
||||
"Créez votre météo personnelle sur 4 axes clés (Performance, Moral, Flux, Création de valeur) et partagez-la avec votre équipe pour une meilleure visibilité de votre état.",
|
||||
features: [
|
||||
'4 axes : Performance, Moral, Flux, Création de valeur',
|
||||
'Emojis météo pour exprimer votre état visuellement',
|
||||
'Notes globales pour détailler votre ressenti',
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const WORKSHOP_BY_ID = Object.fromEntries(WORKSHOPS.map((w) => [w.id, w])) as Record<
|
||||
WorkshopTypeId,
|
||||
WorkshopConfig
|
||||
>;
|
||||
|
||||
export function getWorkshop(id: WorkshopTypeId): WorkshopConfig {
|
||||
return WORKSHOP_BY_ID[id];
|
||||
}
|
||||
|
||||
export function getSessionPath(id: WorkshopTypeId, sessionId: string): string {
|
||||
return `${getWorkshop(id).path}/${sessionId}`;
|
||||
}
|
||||
|
||||
export function getSessionsTabUrl(id: WorkshopTypeId): string {
|
||||
return `/sessions?tab=${id}`;
|
||||
}
|
||||
|
||||
/** Add workshopType to session objects for unified display. Preserves literal type for type safety. */
|
||||
export function withWorkshopType<T, K extends WorkshopTypeId>(
|
||||
sessions: T[],
|
||||
type: K
|
||||
): (T & { workshopType: K })[] {
|
||||
return sessions.map((s) => ({ ...s, workshopType: type })) as (T & { workshopType: K })[];
|
||||
}
|
||||
Reference in New Issue
Block a user