From cb4873cd4063c41a8ff96e3868d65839d8b296e4 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Fri, 28 Nov 2025 10:48:36 +0100 Subject: [PATCH] feat: add session editing functionality with modal in WorkshopTabs component and enhance session revalidation --- dev.db | Bin 229376 -> 229376 bytes src/actions/moving-motivators.ts | 2 + src/actions/session.ts | 40 ++++++ src/app/sessions/WorkshopTabs.tsx | 222 +++++++++++++++++++++++++++--- 4 files changed, 242 insertions(+), 22 deletions(-) diff --git a/dev.db b/dev.db index 13481d7c4aff160b9c8ee471174689f8e1987aff..06fbd62dcadbd5c1ef2e80bb8c64a6c134459f02 100644 GIT binary patch delta 586 zcmZo@;A?2$n;^{?HBrWyF{&}4HGy$!0@E^k7HMvNTxy87<+?(Wka zbC@I*ee+8)%MwfSi;5KjO%#kwy-IU3Q}Yzuit;m4Qq%JDQl?+bWs;q~)}P6V+tSL! z!pgu>&)md#`!9bct^{TyF4gJm6BtuB3kvMyw2@`DXH3q`%*@X+H!3hNFfd9jD#%YN z$}>w$FG)0l%Vv~S7y@MtL9(S;DaC2&iAILo6L&E!F6A;}@nqmX%HPTFJDu+WV;s=j zyUf%7m@sinKWW0OB!qB*iMD}(70`<52Tho@K;q_B1{Qi|MwSq9!|gzEXKQ8w#-8cy z11+L&oTlH+WfI&Lz{HZkY`~Q`oqYmh;$}gCpPbth zcQGw4 { + const grouped = new Map(); + + sessions.forEach((session) => { + const participant = getParticipant(session).trim().toLowerCase(); + const displayName = getParticipant(session).trim(); + + // Use normalized key but store with original display name + const existing = grouped.get(participant); + if (existing) { + existing.push(session); + } else { + grouped.set(participant, [session]); + } + }); + + // Sort sessions within each group by date + grouped.forEach((sessions) => { + sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()); + }); + + return grouped; +} + export function WorkshopTabs({ swotSessions, motivatorSessions }: WorkshopTabsProps) { const [activeTab, setActiveTab] = useState('all'); @@ -61,9 +93,9 @@ export function WorkshopTabs({ swotSessions, motivatorSessions }: WorkshopTabsPr (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime() ); - // Filter based on active tab + // Filter based on active tab (for non-byPerson tabs) const filteredSessions = - activeTab === 'all' + activeTab === 'all' || activeTab === 'byPerson' ? allSessions : activeTab === 'swot' ? swotSessions @@ -73,10 +105,16 @@ export function WorkshopTabs({ swotSessions, motivatorSessions }: WorkshopTabsPr const ownedSessions = filteredSessions.filter((s) => s.isOwner); const sharedSessions = filteredSessions.filter((s) => !s.isOwner); + // Group by person (all sessions - owned and shared) + const sessionsByPerson = groupByPerson(allSessions); + const sortedPersons = Array.from(sessionsByPerson.entries()).sort((a, b) => + a[0].localeCompare(b[0], 'fr') + ); + return (
{/* Tabs */} -
+
setActiveTab('all')} @@ -84,6 +122,13 @@ export function WorkshopTabs({ swotSessions, motivatorSessions }: WorkshopTabsPr label="Tous" count={allSessions.length} /> + setActiveTab('byPerson')} + icon="👥" + label="Par personne" + count={sessionsByPerson.size} + /> setActiveTab('swot')} @@ -101,7 +146,38 @@ export function WorkshopTabs({ swotSessions, motivatorSessions }: WorkshopTabsPr
{/* Sessions */} - {filteredSessions.length === 0 ? ( + {activeTab === 'byPerson' ? ( + // By Person View + sortedPersons.length === 0 ? ( +
+ Aucun atelier pour le moment +
+ ) : ( +
+ {sortedPersons.map(([personKey, sessions]) => { + const displayName = getParticipant(sessions[0]); + return ( +
+

+ + {displayName.charAt(0).toUpperCase()} + + {displayName} + + {sessions.length} + +

+
+ {sessions.map((s) => ( + + ))} +
+
+ ); + })} +
+ ) + ) : filteredSessions.length === 0 ? (
Aucun atelier de ce type pour le moment
@@ -175,7 +251,16 @@ function TabButton({ function SessionCard({ session }: { session: AnySession }) { const [showDeleteModal, setShowDeleteModal] = useState(false); + const [showEditModal, setShowEditModal] = useState(false); const [isPending, startTransition] = useTransition(); + + // Edit form state + const [editTitle, setEditTitle] = useState(session.title); + const [editParticipant, setEditParticipant] = useState( + session.workshopType === 'swot' + ? (session as SwotSession).collaborator + : (session as MotivatorSession).participant + ); const isSwot = session.workshopType === 'swot'; const href = isSwot ? `/sessions/${session.id}` : `/motivators/${session.id}`; @@ -199,6 +284,27 @@ function SessionCard({ session }: { session: AnySession }) { }); }; + const handleEdit = () => { + startTransition(async () => { + const result = isSwot + ? await updateSwotSession(session.id, { title: editTitle, collaborator: editParticipant }) + : await updateMotivatorSession(session.id, { title: editTitle, participant: editParticipant }); + + if (result.success) { + setShowEditModal(false); + } else { + console.error('Error updating session:', result.error); + } + }); + }; + + const openEditModal = () => { + // Reset form values when opening + setEditTitle(session.title); + setEditParticipant(participant); + setShowEditModal(true); + }; + return ( <>
@@ -289,24 +395,96 @@ function SessionCard({ session }: { session: AnySession }) { - {/* Delete button - only for owner */} + {/* Action buttons - only for owner */} {session.isOwner && ( - +
+ + +
)}
+ {/* Edit modal */} + setShowEditModal(false)} + title="Modifier l'atelier" + size="sm" + > +
{ + e.preventDefault(); + handleEdit(); + }} + className="space-y-4" + > +
+ + setEditTitle(e.target.value)} + placeholder="Titre de l'atelier" + required + /> +
+
+ + setEditParticipant(e.target.value)} + placeholder={isSwot ? 'Nom du collaborateur' : 'Nom du participant'} + required + /> +
+ + + + +
+
+ {/* Delete confirmation modal */}