chore: clean up code formatting and remove unnecessary whitespace across multiple files for improved readability

This commit is contained in:
Julien Froidefond
2025-12-05 11:05:14 +01:00
parent b3157fffbd
commit 71d850c985
65 changed files with 347 additions and 505 deletions

View File

@@ -109,4 +109,3 @@ export default function LoginPage() {
</div>
);
}

View File

@@ -170,4 +170,3 @@ export default function RegisterPage() {
</div>
);
}

View File

@@ -1,4 +1,3 @@
import { handlers } from '@/lib/auth';
export const { GET, POST } = handlers;

View File

@@ -22,4 +22,3 @@ export async function POST(request: Request) {
return NextResponse.json({ error: 'Erreur lors de la création du compte' }, { status: 500 });
}
}

View File

@@ -1,18 +1,12 @@
import { auth } from '@/lib/auth';
import {
canAccessMotivatorSession,
getMotivatorSessionEvents,
} from '@/services/moving-motivators';
import { canAccessMotivatorSession, getMotivatorSessionEvents } from '@/services/moving-motivators';
export const dynamic = 'force-dynamic';
// Store active connections per session
const connections = new Map<string, Set<ReadableStreamDefaultController>>();
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {
const { id: sessionId } = await params;
const session = await auth();
@@ -115,4 +109,3 @@ export function broadcastToMotivatorSession(sessionId: string, event: object) {
}
}
}

View File

@@ -6,10 +6,7 @@ export const dynamic = 'force-dynamic';
// Store active connections per session
const connections = new Map<string, Set<ReadableStreamDefaultController>>();
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {
const { id: sessionId } = await params;
const session = await auth();
@@ -112,4 +109,3 @@ export function broadcastToSession(sessionId: string, event: object) {
}
}
}

View File

@@ -45,10 +45,7 @@ export async function POST(request: Request) {
const { title, collaborator } = body;
if (!title || !collaborator) {
return NextResponse.json(
{ error: 'Titre et collaborateur requis' },
{ status: 400 }
);
return NextResponse.json({ error: 'Titre et collaborateur requis' }, { status: 400 });
}
const newSession = await prisma.session.create({
@@ -68,4 +65,3 @@ export async function POST(request: Request) {
);
}
}

View File

@@ -107,4 +107,3 @@ export function EditableMotivatorTitle({
</button>
);
}

View File

@@ -49,11 +49,7 @@ export default async function MotivatorSessionPage({ params }: MotivatorSessionP
isOwner={session.isOwner}
/>
<div className="mt-2">
<CollaboratorDisplay
collaborator={session.resolvedParticipant}
size="lg"
showEmail
/>
<CollaboratorDisplay collaborator={session.resolvedParticipant} size="lg" showEmail />
</div>
</div>
<div className="flex items-center gap-3">
@@ -80,13 +76,8 @@ export default async function MotivatorSessionPage({ params }: MotivatorSessionP
isOwner={session.isOwner}
canEdit={session.canEdit}
>
<MotivatorBoard
sessionId={session.id}
cards={session.cards}
canEdit={session.canEdit}
/>
<MotivatorBoard sessionId={session.id} cards={session.cards} canEdit={session.canEdit} />
</MotivatorLiveWrapper>
</main>
);
}

View File

@@ -2,7 +2,15 @@
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, Input } from '@/components/ui';
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
Button,
Input,
} from '@/components/ui';
import { createMotivatorSession } from '@/actions/moving-motivators';
export default function NewMotivatorSessionPage() {
@@ -99,4 +107,3 @@ export default function NewMotivatorSessionPage() {
</main>
);
}

View File

@@ -10,8 +10,8 @@ export default function Home() {
Vos ateliers, <span className="text-primary">réinventés</span>
</h1>
<p className="mx-auto mb-8 max-w-2xl text-lg text-muted">
Des outils interactifs et collaboratifs pour accompagner vos équipes.
Analysez, comprenez et faites progresser vos collaborateurs avec des ateliers modernes.
Des outils interactifs et collaboratifs pour accompagner vos équipes. Analysez,
comprenez et faites progresser vos collaborateurs avec des ateliers modernes.
</p>
</section>
@@ -46,7 +46,7 @@ export default function Home() {
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',
"Évaluation de l'influence positive/négative",
'Récapitulatif personnalisé des motivations',
]}
accentColor="#8b5cf6"
@@ -73,8 +73,9 @@ export default function Home() {
Pourquoi faire un SWOT ?
</h3>
<p className="text-muted mb-4">
L&apos;analyse SWOT est un outil puissant pour prendre du recul sur une situation professionnelle.
Elle permet de dresser un portrait objectif et structuré, base indispensable pour définir des actions pertinentes.
L&apos;analyse SWOT est un outil puissant pour prendre du recul sur une situation
professionnelle. Elle permet de dresser un portrait objectif et structuré, base
indispensable pour définir des actions pertinentes.
</p>
<ul className="space-y-2 text-sm text-muted">
<li className="flex items-start gap-2">
@@ -105,15 +106,21 @@ export default function Home() {
<div className="grid grid-cols-2 gap-4">
<div className="rounded-lg bg-green-500/10 p-3 border border-green-500/20">
<p className="font-semibold text-green-600 text-sm mb-1">💪 Forces</p>
<p className="text-xs text-muted">Compétences, talents, réussites, qualités distinctives</p>
<p className="text-xs text-muted">
Compétences, talents, réussites, qualités distinctives
</p>
</div>
<div className="rounded-lg bg-orange-500/10 p-3 border border-orange-500/20">
<p className="font-semibold text-orange-600 text-sm mb-1"> Faiblesses</p>
<p className="text-xs text-muted">Lacunes, difficultés récurrentes, axes de progression</p>
<p className="text-xs text-muted">
Lacunes, difficultés récurrentes, axes de progression
</p>
</div>
<div className="rounded-lg bg-blue-500/10 p-3 border border-blue-500/20">
<p className="font-semibold text-blue-600 text-sm mb-1">🚀 Opportunités</p>
<p className="text-xs text-muted">Projets, formations, évolutions, nouveaux défis</p>
<p className="text-xs text-muted">
Projets, formations, évolutions, nouveaux défis
</p>
</div>
<div className="rounded-lg bg-red-500/10 p-3 border border-red-500/20">
<p className="font-semibold text-red-600 text-sm mb-1">🛡 Menaces</p>
@@ -129,10 +136,26 @@ export default function Home() {
Comment ça marche ?
</h3>
<div className="grid md:grid-cols-4 gap-4">
<StepCard number={1} title="Remplir la matrice" description="Identifiez ensemble les éléments de chaque quadrant lors d'un échange constructif" />
<StepCard number={2} title="Prioriser" description="Classez les éléments par importance et impact pour concentrer les efforts" />
<StepCard number={3} title="Croiser" description="Reliez les forces aux opportunités, anticipez les menaces avec les atouts" />
<StepCard number={4} title="Agir" description="Définissez des actions concrètes avec des échéances et des responsables" />
<StepCard
number={1}
title="Remplir la matrice"
description="Identifiez ensemble les éléments de chaque quadrant lors d'un échange constructif"
/>
<StepCard
number={2}
title="Prioriser"
description="Classez les éléments par importance et impact pour concentrer les efforts"
/>
<StepCard
number={3}
title="Croiser"
description="Reliez les forces aux opportunités, anticipez les menaces avec les atouts"
/>
<StepCard
number={4}
title="Agir"
description="Définissez des actions concrètes avec des échéances et des responsables"
/>
</div>
</div>
</div>
@@ -156,8 +179,9 @@ export default function Home() {
Pourquoi explorer ses motivations ?
</h3>
<p className="text-muted mb-4">
Créé par Jurgen Appelo (Management 3.0), cet exercice révèle les motivations intrinsèques qui nous animent.
Comprendre ce qui nous motive permet de mieux s&apos;épanouir et d&apos;aligner nos missions avec nos aspirations profondes.
Créé par Jurgen Appelo (Management 3.0), cet exercice révèle les motivations
intrinsèques qui nous animent. Comprendre ce qui nous motive permet de mieux
s&apos;épanouir et d&apos;aligner nos missions avec nos aspirations profondes.
</p>
<ul className="space-y-2 text-sm text-muted">
<li className="flex items-start gap-2">
@@ -206,20 +230,20 @@ export default function Home() {
Comment ça marche ?
</h3>
<div className="grid md:grid-cols-3 gap-4">
<StepCard
number={1}
title="Classer par importance"
description="Ordonnez les 10 cartes de la moins importante (gauche) à la plus importante (droite) pour vous"
<StepCard
number={1}
title="Classer par importance"
description="Ordonnez les 10 cartes de la moins importante (gauche) à la plus importante (droite) pour vous"
/>
<StepCard
number={2}
title="Évaluer l'influence"
description="Pour chaque motivation, indiquez si votre situation actuelle l'impacte positivement ou négativement"
<StepCard
number={2}
title="Évaluer l'influence"
description="Pour chaque motivation, indiquez si votre situation actuelle l'impacte positivement ou négativement"
/>
<StepCard
number={3}
title="Analyser et discuter"
description="Le récapitulatif révèle les motivations clés et les points de vigilance pour un échange constructif"
<StepCard
number={3}
title="Analyser et discuter"
description="Le récapitulatif révèle les motivations clés et les points de vigilance pour un échange constructif"
/>
</div>
</div>
@@ -279,9 +303,7 @@ function WorkshopCard({
newHref: string;
}) {
return (
<div
className="group relative overflow-hidden rounded-2xl border-2 border-border bg-card p-8 transition-all hover:border-primary/50 hover:shadow-xl"
>
<div className="group relative overflow-hidden rounded-2xl border-2 border-border bg-card p-8 transition-all hover:border-primary/50 hover:shadow-xl">
{/* Accent gradient */}
<div
className="absolute inset-x-0 top-0 h-1 opacity-80"
@@ -313,7 +335,12 @@ function WorkshopCard({
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 13l4 4L19 7"
/>
</svg>
{feature}
</li>
@@ -380,22 +407,16 @@ function StepCard({
);
}
function MotivatorPill({
icon,
name,
color,
}: {
icon: string;
name: string;
color: string;
}) {
function MotivatorPill({ icon, name, color }: { icon: string; name: string; color: string }) {
return (
<div
className="flex items-center gap-2 px-3 py-1.5 rounded-full"
style={{ backgroundColor: `${color}15`, border: `1px solid ${color}30` }}
>
<span>{icon}</span>
<span className="font-medium" style={{ color }}>{name}</span>
<span className="font-medium" style={{ color }}>
{name}
</span>
</div>
);
}

View File

@@ -12,9 +12,7 @@ export function PasswordForm() {
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
const canSubmit =
currentPassword.length > 0 &&
newPassword.length >= 6 &&
newPassword === confirmPassword;
currentPassword.length > 0 && newPassword.length >= 6 && newPassword === confirmPassword;
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
@@ -58,10 +56,7 @@ export function PasswordForm() {
</div>
<div>
<label
htmlFor="newPassword"
className="mb-1.5 block text-sm font-medium text-foreground"
>
<label htmlFor="newPassword" className="mb-1.5 block text-sm font-medium text-foreground">
Nouveau mot de passe
</label>
<Input
@@ -90,17 +85,13 @@ export function PasswordForm() {
required
/>
{confirmPassword && newPassword !== confirmPassword && (
<p className="mt-1 text-xs text-destructive">
Les mots de passe ne correspondent pas
</p>
<p className="mt-1 text-xs text-destructive">Les mots de passe ne correspondent pas</p>
)}
</div>
{message && (
<p
className={`text-sm ${
message.type === 'success' ? 'text-success' : 'text-destructive'
}`}
className={`text-sm ${message.type === 'success' ? 'text-success' : 'text-destructive'}`}
>
{message.text}
</p>
@@ -112,5 +103,3 @@ export function PasswordForm() {
</form>
);
}

View File

@@ -67,9 +67,7 @@ export function ProfileForm({ initialData }: ProfileFormProps) {
{message && (
<p
className={`text-sm ${
message.type === 'success' ? 'text-success' : 'text-destructive'
}`}
className={`text-sm ${message.type === 'success' ? 'text-success' : 'text-destructive'}`}
>
{message.text}
</p>
@@ -81,5 +79,3 @@ export function ProfileForm({ initialData }: ProfileFormProps) {
</form>
);
}

View File

@@ -38,9 +38,7 @@ export default async function ProfilePage() {
{/* Profile Info */}
<section className="rounded-xl border border-border bg-card p-6">
<div className="mb-6 flex items-start justify-between">
<h2 className="text-xl font-semibold text-foreground">
Informations personnelles
</h2>
<h2 className="text-xl font-semibold text-foreground">Informations personnelles</h2>
<a
href="https://gravatar.com"
target="_blank"
@@ -60,17 +58,13 @@ export default async function ProfilePage() {
{/* Password */}
<section className="rounded-xl border border-border bg-card p-6">
<h2 className="mb-6 text-xl font-semibold text-foreground">
Changer le mot de passe
</h2>
<h2 className="mb-6 text-xl font-semibold text-foreground">Changer le mot de passe</h2>
<PasswordForm />
</section>
{/* Account Info */}
<section className="rounded-xl border border-border bg-card p-6">
<h2 className="mb-4 text-xl font-semibold text-foreground">
Informations du compte
</h2>
<h2 className="mb-4 text-xl font-semibold text-foreground">Informations du compte</h2>
<div className="space-y-3 text-sm">
<div className="flex justify-between">
<span className="text-muted">ID du compte</span>
@@ -92,4 +86,3 @@ export default async function ProfilePage() {
</main>
);
}

View File

@@ -3,7 +3,15 @@
import { useState, useTransition } from 'react';
import Link from 'next/link';
import { useSearchParams, useRouter } from 'next/navigation';
import { Card, Badge, Button, Modal, ModalFooter, Input, CollaboratorDisplay } from '@/components/ui';
import {
Card,
Badge,
Button,
Modal,
ModalFooter,
Input,
CollaboratorDisplay,
} from '@/components/ui';
import { deleteSwotSession, updateSwotSession } from '@/actions/session';
import { deleteMotivatorSession, updateMotivatorSession } from '@/actions/moving-motivators';
@@ -104,10 +112,10 @@ function getGroupKey(session: AnySession): string {
// Group sessions by participant (using matched user ID when available)
function groupByPerson(sessions: AnySession[]): Map<string, AnySession[]> {
const grouped = new Map<string, AnySession[]>();
sessions.forEach((session) => {
const key = getGroupKey(session);
const existing = grouped.get(key);
if (existing) {
existing.push(session);
@@ -115,24 +123,23 @@ function groupByPerson(sessions: AnySession[]): Map<string, AnySession[]> {
grouped.set(key, [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 searchParams = useSearchParams();
const router = useRouter();
// Get tab from URL or default to 'all'
const tabParam = searchParams.get('tab');
const activeTab: WorkshopType = tabParam && VALID_TABS.includes(tabParam as WorkshopType)
? (tabParam as WorkshopType)
: 'all';
const activeTab: WorkshopType =
tabParam && VALID_TABS.includes(tabParam as WorkshopType) ? (tabParam as WorkshopType) : 'all';
const setActiveTab = (tab: WorkshopType) => {
const params = new URLSearchParams(searchParams.toString());
@@ -205,9 +212,7 @@ export function WorkshopTabs({ swotSessions, motivatorSessions }: WorkshopTabsPr
{activeTab === 'byPerson' ? (
// By Person View
sortedPersons.length === 0 ? (
<div className="text-center py-12 text-muted">
Aucun atelier pour le moment
</div>
<div className="text-center py-12 text-muted">Aucun atelier pour le moment</div>
) : (
<div className="space-y-8">
{sortedPersons.map(([personKey, sessions]) => {
@@ -231,9 +236,7 @@ export function WorkshopTabs({ swotSessions, motivatorSessions }: WorkshopTabsPr
</div>
)
) : filteredSessions.length === 0 ? (
<div className="text-center py-12 text-muted">
Aucun atelier de ce type pour le moment
</div>
<div className="text-center py-12 text-muted">Aucun atelier de ce type pour le moment</div>
) : (
<div className="space-y-8">
{/* My Sessions */}
@@ -287,9 +290,10 @@ function TabButton({
onClick={onClick}
className={`
flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition-colors
${active
? 'bg-primary text-primary-foreground'
: 'text-muted hover:bg-card-hover hover:text-foreground'
${
active
? 'bg-primary text-primary-foreground'
: 'text-muted hover:bg-card-hover hover:text-foreground'
}
`}
>
@@ -306,7 +310,7 @@ 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(
@@ -328,7 +332,7 @@ function SessionCard({ session }: { session: AnySession }) {
const result = isSwot
? await deleteSwotSession(session.id)
: await deleteMotivatorSession(session.id);
if (result.success) {
setShowDeleteModal(false);
} else {
@@ -341,8 +345,11 @@ function SessionCard({ session }: { session: AnySession }) {
startTransition(async () => {
const result = isSwot
? await updateSwotSession(session.id, { title: editTitle, collaborator: editParticipant })
: await updateMotivatorSession(session.id, { title: editTitle, participant: editParticipant });
: await updateMotivatorSession(session.id, {
title: editTitle,
participant: editParticipant,
});
if (result.success) {
setShowEditModal(false);
} else {
@@ -372,14 +379,13 @@ function SessionCard({ session }: { session: AnySession }) {
{/* Header: Icon + Title + Role badge */}
<div className="flex items-center gap-2 mb-2">
<span className="text-xl">{icon}</span>
<h3 className="font-semibold text-foreground line-clamp-1 flex-1">
{session.title}
</h3>
<h3 className="font-semibold text-foreground line-clamp-1 flex-1">{session.title}</h3>
{!session.isOwner && (
<span
className="text-xs px-1.5 py-0.5 rounded"
style={{
backgroundColor: session.role === 'EDITOR' ? 'rgba(6,182,212,0.1)' : 'rgba(234,179,8,0.1)',
backgroundColor:
session.role === 'EDITOR' ? 'rgba(6,182,212,0.1)' : 'rgba(234,179,8,0.1)',
color: session.role === 'EDITOR' ? '#06b6d4' : '#eab308',
}}
>
@@ -390,12 +396,11 @@ function SessionCard({ session }: { session: AnySession }) {
{/* Participant + Owner info */}
<div className="mb-3 flex items-center gap-2">
<CollaboratorDisplay
collaborator={getResolvedCollaborator(session)}
size="sm"
/>
<CollaboratorDisplay collaborator={getResolvedCollaborator(session)} size="sm" />
{!session.isOwner && (
<span className="text-xs text-muted">· par {session.user.name || session.user.email}</span>
<span className="text-xs text-muted">
· par {session.user.name || session.user.email}
</span>
)}
</div>
@@ -441,9 +446,7 @@ function SessionCard({ session }: { session: AnySession }) {
</div>
))}
{session.shares.length > 3 && (
<span className="text-[10px] text-muted">
+{session.shares.length - 3}
</span>
<span className="text-[10px] text-muted">+{session.shares.length - 3}</span>
)}
</div>
</div>
@@ -464,7 +467,12 @@ function SessionCard({ session }: { session: AnySession }) {
title="Modifier"
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
/>
</svg>
</button>
<button
@@ -477,7 +485,12 @@ function SessionCard({ session }: { session: AnySession }) {
title="Supprimer"
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</div>
@@ -511,7 +524,10 @@ function SessionCard({ session }: { session: AnySession }) {
/>
</div>
<div>
<label htmlFor="edit-participant" className="block text-sm font-medium text-foreground mb-1">
<label
htmlFor="edit-participant"
className="block text-sm font-medium text-foreground mb-1"
>
{isSwot ? 'Collaborateur' : 'Participant'}
</label>
<Input
@@ -550,24 +566,17 @@ function SessionCard({ session }: { session: AnySession }) {
>
<div className="space-y-4">
<p className="text-muted">
Êtes-vous sûr de vouloir supprimer l&apos;atelier <strong className="text-foreground">&quot;{session.title}&quot;</strong> ?
Êtes-vous sûr de vouloir supprimer l&apos;atelier{' '}
<strong className="text-foreground">&quot;{session.title}&quot;</strong> ?
</p>
<p className="text-sm text-destructive">
Cette action est irréversible. Toutes les données seront perdues.
</p>
<ModalFooter>
<Button
variant="ghost"
onClick={() => setShowDeleteModal(false)}
disabled={isPending}
>
<Button variant="ghost" onClick={() => setShowDeleteModal(false)} disabled={isPending}>
Annuler
</Button>
<Button
variant="destructive"
onClick={handleDelete}
disabled={isPending}
>
<Button variant="destructive" onClick={handleDelete} disabled={isPending}>
{isPending ? 'Suppression...' : 'Supprimer'}
</Button>
</ModalFooter>
@@ -576,4 +585,3 @@ function SessionCard({ session }: { session: AnySession }) {
</>
);
}

View File

@@ -80,13 +80,8 @@ export default async function SessionPage({ params }: SessionPageProps) {
isOwner={session.isOwner}
canEdit={session.canEdit}
>
<SwotBoard
sessionId={session.id}
items={session.items}
actions={session.actions}
/>
<SwotBoard sessionId={session.id} items={session.items} actions={session.actions} />
</SessionLiveWrapper>
</main>
);
}

View File

@@ -2,7 +2,15 @@
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, Input } from '@/components/ui';
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
Button,
Input,
} from '@/components/ui';
export default function NewSessionPage() {
const router = useRouter();
@@ -100,4 +108,3 @@ export default function NewSessionPage() {
</main>
);
}

View File

@@ -62,9 +62,7 @@ export default async function SessionsPage() {
<div className="mb-8 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h1 className="text-3xl font-bold text-foreground">Mes Ateliers</h1>
<p className="mt-1 text-muted">
Tous vos ateliers en un seul endroit
</p>
<p className="mt-1 text-muted">Tous vos ateliers en un seul endroit</p>
</div>
<div className="flex gap-2">
<Link href="/sessions/new">
@@ -90,7 +88,8 @@ export default async function SessionsPage() {
Commencez votre premier atelier
</h2>
<p className="text-muted mb-6 max-w-md mx-auto">
Créez un atelier SWOT pour analyser les forces et faiblesses, ou un Moving Motivators pour découvrir les motivations de vos collaborateurs.
Créez un atelier SWOT pour analyser les forces et faiblesses, ou un Moving Motivators
pour découvrir les motivations de vos collaborateurs.
</p>
<div className="flex gap-3 justify-center">
<Link href="/sessions/new">
@@ -109,10 +108,7 @@ export default async function SessionsPage() {
</Card>
) : (
<Suspense fallback={<WorkshopTabsSkeleton />}>
<WorkshopTabs
swotSessions={allSwotSessions}
motivatorSessions={allMotivatorSessions}
/>
<WorkshopTabs swotSessions={allSwotSessions} motivatorSessions={allMotivatorSessions} />
</Suspense>
)}
</main>

View File

@@ -54,16 +54,13 @@ export default async function UsersPage() {
<div className="text-sm text-muted">Sessions totales</div>
</div>
<div className="rounded-xl border border-border bg-card p-4">
<div className="text-2xl font-bold text-opportunity">
{avgSessionsPerUser.toFixed(1)}
</div>
<div className="text-2xl font-bold text-opportunity">{avgSessionsPerUser.toFixed(1)}</div>
<div className="text-sm text-muted">Moy. par user</div>
</div>
<div className="rounded-xl border border-border bg-card p-4">
<div className="text-2xl font-bold text-accent">
{users.reduce(
(acc, u) =>
acc + u._count.sharedSessions + u._count.sharedMotivatorSessions,
(acc, u) => acc + u._count.sharedSessions + u._count.sharedMotivatorSessions,
0
)}
</div>
@@ -74,10 +71,8 @@ export default async function UsersPage() {
{/* Users List */}
<div className="space-y-3">
{users.map((user) => {
const totalUserSessions =
user._count.sessions + user._count.motivatorSessions;
const totalShares =
user._count.sharedSessions + user._count.sharedMotivatorSessions;
const totalUserSessions = user._count.sessions + user._count.motivatorSessions;
const totalShares = user._count.sharedSessions + user._count.sharedMotivatorSessions;
const isCurrentUser = user.id === session.user?.id;
return (
@@ -194,16 +189,12 @@ export default async function UsersPage() {
<div className="text-sm font-medium text-foreground">
{totalUserSessions} session{totalUserSessions !== 1 ? 's' : ''}
</div>
<div className="text-xs text-muted">
{formatRelativeTime(user.createdAt)}
</div>
<div className="text-xs text-muted">{formatRelativeTime(user.createdAt)}</div>
</div>
{/* Date Info */}
<div className="hidden flex-col items-end sm:flex">
<div className="text-sm text-foreground">
{formatRelativeTime(user.createdAt)}
</div>
<div className="text-sm text-foreground">{formatRelativeTime(user.createdAt)}</div>
<div className="text-xs text-muted">
{new Date(user.createdAt).toLocaleDateString('fr-FR')}
</div>
@@ -217,9 +208,7 @@ export default async function UsersPage() {
{users.length === 0 && (
<div className="flex flex-col items-center justify-center rounded-xl border border-border bg-card py-16">
<div className="text-4xl">👥</div>
<div className="mt-4 text-lg font-medium text-foreground">
Aucun utilisateur
</div>
<div className="mt-4 text-lg font-medium text-foreground">Aucun utilisateur</div>
<div className="mt-1 text-sm text-muted">
Les utilisateurs apparaîtront ici une fois inscrits
</div>
@@ -228,4 +217,3 @@ export default async function UsersPage() {
</main>
);
}