From 09a849279b27539293acfa03b8d174563468e4c8 Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Tue, 3 Mar 2026 14:15:43 +0100 Subject: [PATCH] refactor: add SessionPageHeader and apply to all 6 session detail pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create SessionPageHeader component (breadcrumb + editable title + collaborator + badges + date) - Embed UPDATE_FN map internally, keyed by workshopType — no prop drilling - Replace duplicated header blocks in sessions, motivators, year-review, weather, weekly-checkin, gif-mood Co-Authored-By: Claude Sonnet 4.6 --- src/app/gif-mood/[id]/page.tsx | 49 +++---------- src/app/motivators/[id]/page.tsx | 64 +++++------------ src/app/sessions/[id]/page.tsx | 62 ++++------------ src/app/teams/[id]/page.tsx | 36 ++++------ src/app/weather/[id]/page.tsx | 49 +++---------- src/app/weekly-checkin/[id]/page.tsx | 54 ++++---------- src/app/year-review/[id]/page.tsx | 62 ++++------------ src/components/ui/SessionPageHeader.tsx | 95 +++++++++++++++++++++++++ src/components/ui/index.ts | 1 + 9 files changed, 191 insertions(+), 281 deletions(-) create mode 100644 src/components/ui/SessionPageHeader.tsx diff --git a/src/app/gif-mood/[id]/page.tsx b/src/app/gif-mood/[id]/page.tsx index a711504..ec4e4e9 100644 --- a/src/app/gif-mood/[id]/page.tsx +++ b/src/app/gif-mood/[id]/page.tsx @@ -1,11 +1,9 @@ import { notFound } from 'next/navigation'; -import Link from 'next/link'; import { auth } from '@/lib/auth'; -import { getWorkshop, getSessionsTabUrl } from '@/lib/workshops'; import { getGifMoodSessionById } from '@/services/gif-mood'; import { getUserTeams } from '@/services/teams'; import { GifMoodBoard, GifMoodLiveWrapper } from '@/components/gif-mood'; -import { Badge, EditableGifMoodTitle } from '@/components/ui'; +import { Badge, SessionPageHeader } from '@/components/ui'; interface GifMoodSessionPageProps { params: Promise<{ id: string }>; @@ -29,41 +27,16 @@ export default async function GifMoodSessionPage({ params }: GifMoodSessionPageP return (
- {/* Header */} -
-
- - {getWorkshop('gif-mood').labelShort} - - / - {session.title} - {!session.isOwner && ( - - Partagé par {session.user.name || session.user.email} - - )} -
- -
-
- -
-
- {session.items.length} GIFs - - {new Date(session.date).toLocaleDateString('fr-FR', { - day: 'numeric', - month: 'long', - year: 'numeric', - })} - -
-
-
+ {session.items.length} GIFs} + /> {/* Live Wrapper + Board */} ; @@ -32,50 +29,21 @@ export default async function MotivatorSessionPage({ params }: MotivatorSessionP return (
- {/* Header */} -
-
- - {getWorkshop('motivators').label} - - / - {session.title} - {!session.isOwner && ( - - Partagé par {session.user.name || session.user.email} - - )} -
- -
-
- -
- -
-
-
- - {session.cards.filter((c) => c.influence !== 0).length} / 10 évalués - - - {new Date(session.date).toLocaleDateString('fr-FR', { - day: 'numeric', - month: 'long', - year: 'numeric', - })} - -
-
-
+ + {session.cards.filter((c) => c.influence !== 0).length} / 10 évalués + + } + /> {/* Live Wrapper + Board */} ; @@ -32,49 +29,20 @@ export default async function SessionPage({ params }: SessionPageProps) { return (
- {/* Header */} -
-
- - {getWorkshop('swot').labelShort} - - / - {session.title} - {!session.isOwner && ( - - Partagé par {session.user.name || session.user.email} - - )} -
- -
-
- -
- -
-
-
- {session.items.length} items - {session.actions.length} actions - - {new Date(session.date).toLocaleDateString('fr-FR', { - day: 'numeric', - month: 'long', - year: 'numeric', - })} - -
-
-
+ + {session.items.length} items + {session.actions.length} actions + } + /> {/* Live Session Wrapper */} - {/* Header */} -
-
- - ← Retour aux équipes - -
-
-
-

- 👥 - {team.name} -

- {team.description &&

{team.description}

} -
- {isAdmin && ( +
+ + ← Retour aux équipes + +
+
- )} -
- + ) : undefined + } + /> {/* Members Section */} diff --git a/src/app/weather/[id]/page.tsx b/src/app/weather/[id]/page.tsx index 48aec9b..224ab2f 100644 --- a/src/app/weather/[id]/page.tsx +++ b/src/app/weather/[id]/page.tsx @@ -1,7 +1,5 @@ import { notFound } from 'next/navigation'; -import Link from 'next/link'; import { auth } from '@/lib/auth'; -import { getWorkshop, getSessionsTabUrl } from '@/lib/workshops'; import { getWeatherSessionById, getPreviousWeatherEntriesForUsers, @@ -15,7 +13,7 @@ import { WeatherAverageBar, WeatherTrendChart, } from '@/components/weather'; -import { Badge, EditableWeatherTitle } from '@/components/ui'; +import { Badge, SessionPageHeader } from '@/components/ui'; interface WeatherSessionPageProps { params: Promise<{ id: string }>; @@ -45,41 +43,16 @@ export default async function WeatherSessionPage({ params }: WeatherSessionPageP return (
- {/* Header */} -
-
- - {getWorkshop('weather').labelShort} - - / - {session.title} - {!session.isOwner && ( - - Partagé par {session.user.name || session.user.email} - - )} -
- -
-
- -
-
- {session.entries.length} membres - - {new Date(session.date).toLocaleDateString('fr-FR', { - day: 'numeric', - month: 'long', - year: 'numeric', - })} - -
-
-
+ {session.entries.length} membres} + /> {/* Info sur les catégories */} diff --git a/src/app/weekly-checkin/[id]/page.tsx b/src/app/weekly-checkin/[id]/page.tsx index 04af55f..91ac446 100644 --- a/src/app/weekly-checkin/[id]/page.tsx +++ b/src/app/weekly-checkin/[id]/page.tsx @@ -1,7 +1,5 @@ import { notFound } from 'next/navigation'; -import Link from 'next/link'; import { auth } from '@/lib/auth'; -import { getWorkshop, getSessionsTabUrl } from '@/lib/workshops'; import { getWeeklyCheckInSessionById } from '@/services/weekly-checkin'; import { getUserTeams } from '@/services/teams'; import type { ResolvedCollaborator } from '@/services/auth'; @@ -9,8 +7,7 @@ import { getUserOKRsForPeriod } from '@/services/okrs'; import { getCurrentQuarterPeriod } from '@/lib/okr-utils'; import { WeeklyCheckInBoard, WeeklyCheckInLiveWrapper } from '@/components/weekly-checkin'; import { CurrentQuarterOKRs } from '@/components/weekly-checkin/CurrentQuarterOKRs'; -import { Badge, CollaboratorDisplay } from '@/components/ui'; -import { EditableWeeklyCheckInTitle } from '@/components/ui'; +import { Badge, SessionPageHeader } from '@/components/ui'; interface WeeklyCheckInSessionPageProps { params: Promise<{ id: string }>; @@ -48,44 +45,17 @@ export default async function WeeklyCheckInSessionPage({ params }: WeeklyCheckIn return (
- {/* Header */} -
-
- - {getWorkshop('weekly-checkin').label} - - / - {session.title} - {!session.isOwner && ( - - Partagé par {session.user.name || session.user.email} - - )} -
- -
-
- -
- -
-
-
- {session.items.length} items - - {new Date(session.date).toLocaleDateString('fr-FR', { - day: 'numeric', - month: 'long', - year: 'numeric', - })} - -
-
-
+ {session.items.length} items} + /> {/* Current Quarter OKRs - editable by participant or team admin */} {currentQuarterOKRs.length > 0 && ( diff --git a/src/app/year-review/[id]/page.tsx b/src/app/year-review/[id]/page.tsx index 8c18227..1a32781 100644 --- a/src/app/year-review/[id]/page.tsx +++ b/src/app/year-review/[id]/page.tsx @@ -1,13 +1,10 @@ import { notFound } from 'next/navigation'; -import Link from 'next/link'; import { auth } from '@/lib/auth'; -import { getWorkshop, getSessionsTabUrl } from '@/lib/workshops'; import { getYearReviewSessionById } from '@/services/year-review'; import { getUserTeams } from '@/services/teams'; import type { ResolvedCollaborator } from '@/services/auth'; import { YearReviewBoard, YearReviewLiveWrapper } from '@/components/year-review'; -import { Badge, CollaboratorDisplay } from '@/components/ui'; -import { EditableYearReviewTitle } from '@/components/ui'; +import { Badge, SessionPageHeader } from '@/components/ui'; interface YearReviewSessionPageProps { params: Promise<{ id: string }>; @@ -32,49 +29,20 @@ export default async function YearReviewSessionPage({ params }: YearReviewSessio return (
- {/* Header */} -
-
- - {getWorkshop('year-review').label} - - / - {session.title} - {!session.isOwner && ( - - Partagé par {session.user.name || session.user.email} - - )} -
- -
-
- -
- -
-
-
- {session.items.length} items - Année {session.year} - - {new Date(session.updatedAt).toLocaleDateString('fr-FR', { - day: 'numeric', - month: 'long', - year: 'numeric', - })} - -
-
-
+ + {session.items.length} items + Année {session.year} + } + /> {/* Live Wrapper + Board */} Promise<{ success: boolean; error?: string }>; + +const UPDATE_FN: Record = { + 'swot': updateSessionTitle, + 'motivators': (id, title) => updateMotivatorSession(id, { title }), + 'year-review': (id, title) => updateYearReviewSession(id, { title }), + 'weekly-checkin': (id, title) => updateWeeklyCheckInSession(id, { title }), + 'weather': (id, title) => updateWeatherSession(id, { title }), + 'gif-mood': (id, title) => updateGifMoodSession(id, { title }), +}; + +interface SessionPageHeaderProps { + workshopType: WorkshopTypeId; + sessionId: string; + sessionTitle: string; + isOwner: boolean; + canEdit: boolean; + ownerUser: { name: string | null; email: string }; + date: Date | string; + collaborator?: ResolvedCollaborator | null; + badges?: ReactNode; +} + +export function SessionPageHeader({ + workshopType, + sessionId, + sessionTitle, + isOwner, + canEdit, + ownerUser, + date, + collaborator, + badges, +}: SessionPageHeaderProps) { + const workshop = getWorkshop(workshopType); + + return ( +
+
+ + {workshop.labelShort} + + / + {sessionTitle} + {!isOwner && ( + + Partagé par {ownerUser.name || ownerUser.email} + + )} +
+ +
+
+ + {collaborator && ( +
+ +
+ )} +
+
+ {badges} + + {new Date(date).toLocaleDateString('fr-FR', { + day: 'numeric', + month: 'long', + year: 'numeric', + })} + +
+
+
+ ); +} diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index fe118ae..ec411b4 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -13,6 +13,7 @@ export { EditableGifMoodTitle, } from './EditableTitles'; export { PageHeader } from './PageHeader'; +export { SessionPageHeader } from './SessionPageHeader'; export { Input } from './Input'; export { ParticipantInput } from './ParticipantInput'; export { Modal, ModalFooter } from './Modal';