feat: add help panel to SwotQuadrant component for enhanced user guidance and update exports in swot index
This commit is contained in:
161
src/components/swot/QuadrantHelp.tsx
Normal file
161
src/components/swot/QuadrantHelp.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
import { forwardRef, useState, useTransition, ReactNode } from 'react';
|
import { forwardRef, useState, useTransition, ReactNode } from 'react';
|
||||||
import type { SwotCategory } from '@prisma/client';
|
import type { SwotCategory } from '@prisma/client';
|
||||||
import { createSwotItem } from '@/actions/swot';
|
import { createSwotItem } from '@/actions/swot';
|
||||||
|
import { QuadrantHelpPanel } from './QuadrantHelp';
|
||||||
|
|
||||||
interface SwotQuadrantProps {
|
interface SwotQuadrantProps {
|
||||||
category: SwotCategory;
|
category: SwotCategory;
|
||||||
@@ -41,6 +42,7 @@ export const SwotQuadrant = forwardRef<HTMLDivElement, SwotQuadrantProps>(
|
|||||||
const [isAdding, setIsAdding] = useState(false);
|
const [isAdding, setIsAdding] = useState(false);
|
||||||
const [newContent, setNewContent] = useState('');
|
const [newContent, setNewContent] = useState('');
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
|
const [showHelp, setShowHelp] = useState(false);
|
||||||
|
|
||||||
const styles = categoryStyles[category];
|
const styles = categoryStyles[category];
|
||||||
|
|
||||||
@@ -81,10 +83,25 @@ export const SwotQuadrant = forwardRef<HTMLDivElement, SwotQuadrantProps>(
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* 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">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-xl">{icon}</span>
|
<span className="text-xl">{icon}</span>
|
||||||
<h3 className={`font-semibold ${styles.text}`}>{title}</h3>
|
<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>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsAdding(true)}
|
onClick={() => setIsAdding(true)}
|
||||||
@@ -100,6 +117,9 @@ export const SwotQuadrant = forwardRef<HTMLDivElement, SwotQuadrantProps>(
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Help Panel */}
|
||||||
|
<QuadrantHelpPanel category={category} isOpen={showHelp} />
|
||||||
|
|
||||||
{/* Items */}
|
{/* Items */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export { SwotBoard } from './SwotBoard';
|
|||||||
export { SwotQuadrant } from './SwotQuadrant';
|
export { SwotQuadrant } from './SwotQuadrant';
|
||||||
export { SwotCard } from './SwotCard';
|
export { SwotCard } from './SwotCard';
|
||||||
export { ActionPanel } from './ActionPanel';
|
export { ActionPanel } from './ActionPanel';
|
||||||
|
export { QuadrantHelp } from './QuadrantHelp';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user