feat: add help panel to SwotQuadrant component for enhanced user guidance and update exports in swot index

This commit is contained in:
Julien Froidefond
2025-11-27 13:42:17 +01:00
parent 873b3dd9f3
commit 15ea89f477
4 changed files with 183 additions and 1 deletions

BIN
dev.db

Binary file not shown.

View File

@@ -0,0 +1,161 @@
'use client';
import { useState } from 'react';
import type { SwotCategory } from '@prisma/client';
interface HelpContent {
description: string;
examples: string[];
questions: string[];
}
const HELP_CONTENT: Record<SwotCategory, HelpContent> = {
STRENGTH: {
description:
'Les atouts internes et qualités qui distinguent positivement.',
examples: [
'Expertise technique solide',
'Excellentes capacités de communication',
'Leadership naturel',
'Rigueur et organisation',
],
questions: [
'Qu\'est-ce qui le/la distingue ?',
'Quels retours positifs reçoit-il/elle ?',
],
},
WEAKNESS: {
description:
'Les axes d\'amélioration et points à travailler.',
examples: [
'Difficulté à déléguer',
'Gestion du stress à améliorer',
'Communication écrite perfectible',
'Manque de visibilité en réunion',
],
questions: [
'Quels feedbacks constructifs a-t-il/elle reçus ?',
'Quelles situations le/la mettent en difficulté ?',
],
},
OPPORTUNITY: {
description:
'Les facteurs externes favorables à saisir.',
examples: [
'Nouveau projet stratégique',
'Formation disponible',
'Poste ouvert en interne',
'Mentor potentiel identifié',
],
questions: [
'Quelles évolutions pourraient l\'aider ?',
'Quelles ressources sont disponibles ?',
],
},
THREAT: {
description:
'Les risques externes à anticiper.',
examples: [
'Réorganisation menaçant le poste',
'Compétences devenant obsolètes',
'Concurrence interne forte',
'Budget formation réduit',
],
questions: [
'Quels changements pourraient impacter négativement ?',
'Quels risques sont à anticiper ?',
],
},
};
interface QuadrantHelpProps {
category: SwotCategory;
}
export function QuadrantHelp({ category }: QuadrantHelpProps) {
const [isOpen, setIsOpen] = useState(false);
const content = HELP_CONTENT[category];
return (
<button
onClick={() => setIsOpen(!isOpen)}
className={`
flex h-5 w-5 items-center justify-center rounded-full
text-xs font-medium transition-all
${isOpen
? 'bg-foreground/20 text-foreground rotate-45'
: 'bg-foreground/5 text-muted hover:bg-foreground/10 hover:text-foreground'
}
`}
aria-label="Aide"
aria-expanded={isOpen}
>
{isOpen ? '×' : '?'}
</button>
);
}
interface QuadrantHelpPanelProps {
category: SwotCategory;
isOpen: boolean;
}
export function QuadrantHelpPanel({ category, isOpen }: QuadrantHelpPanelProps) {
const content = HELP_CONTENT[category];
return (
<div
className={`
grid transition-all duration-300 ease-in-out
${isOpen ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0'}
`}
>
<div className="overflow-hidden">
<div className="rounded-lg bg-white/40 dark:bg-black/20 p-3 mb-3">
{/* Description */}
<p className="text-xs text-foreground/80 leading-relaxed">
{content.description}
</p>
<div className="mt-3 flex gap-4">
{/* Examples */}
<div className="flex-1">
<h4 className="text-[10px] font-semibold uppercase tracking-wider text-muted mb-1.5">
📝 Exemples
</h4>
<ul className="space-y-0.5">
{content.examples.map((example, i) => (
<li
key={i}
className="flex items-start gap-1.5 text-xs text-foreground/70"
>
<span className="mt-1.5 h-1 w-1 flex-shrink-0 rounded-full bg-current opacity-50" />
{example}
</li>
))}
</ul>
</div>
{/* Questions */}
<div className="flex-1">
<h4 className="text-[10px] font-semibold uppercase tracking-wider text-muted mb-1.5">
💡 Questions
</h4>
<ul className="space-y-1">
{content.questions.map((question, i) => (
<li
key={i}
className="text-xs italic text-foreground/60"
>
{question}
</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -3,6 +3,7 @@
import { forwardRef, useState, useTransition, ReactNode } from 'react';
import type { SwotCategory } from '@prisma/client';
import { createSwotItem } from '@/actions/swot';
import { QuadrantHelpPanel } from './QuadrantHelp';
interface SwotQuadrantProps {
category: SwotCategory;
@@ -41,6 +42,7 @@ export const SwotQuadrant = forwardRef<HTMLDivElement, SwotQuadrantProps>(
const [isAdding, setIsAdding] = useState(false);
const [newContent, setNewContent] = useState('');
const [isPending, startTransition] = useTransition();
const [showHelp, setShowHelp] = useState(false);
const styles = categoryStyles[category];
@@ -81,10 +83,25 @@ export const SwotQuadrant = forwardRef<HTMLDivElement, SwotQuadrantProps>(
{...props}
>
{/* Header */}
<div className="mb-4 flex items-center justify-between">
<div className="mb-3 flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="text-xl">{icon}</span>
<h3 className={`font-semibold ${styles.text}`}>{title}</h3>
<button
onClick={() => setShowHelp(!showHelp)}
className={`
flex h-5 w-5 items-center justify-center rounded-full
text-xs font-medium transition-all
${showHelp
? 'bg-foreground/20 text-foreground'
: 'bg-foreground/5 text-muted hover:bg-foreground/10 hover:text-foreground'
}
`}
aria-label="Aide"
aria-expanded={showHelp}
>
{showHelp ? '×' : '?'}
</button>
</div>
<button
onClick={() => setIsAdding(true)}
@@ -100,6 +117,9 @@ export const SwotQuadrant = forwardRef<HTMLDivElement, SwotQuadrantProps>(
</button>
</div>
{/* Help Panel */}
<QuadrantHelpPanel category={category} isOpen={showHelp} />
{/* Items */}
<div className="space-y-2">
{children}

View File

@@ -2,4 +2,5 @@ export { SwotBoard } from './SwotBoard';
export { SwotQuadrant } from './SwotQuadrant';
export { SwotCard } from './SwotCard';
export { ActionPanel } from './ActionPanel';
export { QuadrantHelp } from './QuadrantHelp';