diff --git a/src/components/matrix/SkillMatrixTable.jsx b/src/components/matrix/SkillMatrixTable.jsx index 9e1f0c5..4af904c 100644 --- a/src/components/matrix/SkillMatrixTable.jsx +++ b/src/components/matrix/SkillMatrixTable.jsx @@ -1,9 +1,37 @@ +import { useState } from 'react' +import { ChevronDown, ChevronRight, ListCollapse } from 'lucide-react' import { SkillLevelBadge, SkillLevelSelect } from '@/components/SkillLevelBadge' -export function SkillMatrixTable({ skills, members, levels, isAdmin, editing, onEdit, onUpdate, onCancel }) { - const visibleMembers = skills.length === 0 ? [] : members +export function SkillMatrixTable({ categories, skills, members, levels, isAdmin, currentUserId, editing, onEdit, onUpdate, onCancel }) { + const [collapsed, setCollapsed] = useState(new Set()) - if (visibleMembers.length === 0) { + const grouped = categories + .map((cat) => ({ + ...cat, + catSkills: skills.filter((s) => s.category_id === cat.id), + })) + .filter((g) => g.catSkills.length > 0) + + const allCollapsed = grouped.every((g) => collapsed.has(g.id)) + + function toggleCategory(catId) { + setCollapsed((prev) => { + const next = new Set(prev) + if (next.has(catId)) next.delete(catId) + else next.add(catId) + return next + }) + } + + function toggleAll() { + if (allCollapsed) { + setCollapsed(new Set()) + } else { + setCollapsed(new Set(grouped.map((g) => g.id))) + } + } + + if (members.length === 0) { return (
| Membre | - {skills.map((s) => ( -{s.name} | ++ + Compétence + | + {members.map((m) => ( ++ {m.full_name || m.email} + | ))}
|---|---|---|---|
| - {m.full_name || m.email} - | - {skills.map((s) => { - const key = `${m.id}-${s.id}` - const level = levels[key] - const isEditing = editing === key - return ( -
- {isEditing && isAdmin ? (
- | toggleCategory(g.id)}>
+
+ {isCollapsed ? |
- )
- })}
-
+
+ {counts.map((c, i) =>
+ c > 0 ? (
+
+
+ {c}
+
+ ) : null
+ )}
+
+ |
+ )
+ })}
+ |
| + {s.name} + | + {members.map((m) => { + const key = `${m.id}-${s.id}` + const level = levels[key] + const canEditCell = isAdmin || currentUserId === m.id + const isEditing = editing === key + return ( +
+ {isEditing && canEditCell ? (
+ |
+ )
+ })}
+
- {h.member?.full_name} - {' → '}{h.skill?.name} + Membre : + {' '}{h.member?.full_name || h.member_id?.slice(0, 8)} +
++ Compétence : + {' '}{h.skill?.name}
Par {h.changer?.full_name} — {new Date(h.created_at).toLocaleString()} diff --git a/src/pages/SkillMatrix.jsx b/src/pages/SkillMatrix.jsx index dc6943b..6c08200 100644 --- a/src/pages/SkillMatrix.jsx +++ b/src/pages/SkillMatrix.jsx @@ -6,11 +6,15 @@ import { useMembers } from '@/hooks/useMembers' import { useSkillLevels } from '@/hooks/useSkillLevels' import { SkillMatrixFilters } from '@/components/matrix/SkillMatrixFilters' import { SkillMatrixTable } from '@/components/matrix/SkillMatrixTable' +import { SkillMemberForm } from '@/components/matrix/SkillMemberForm' +import { Download } from 'lucide-react' +import { Button } from '@/components/ui/button' import { toast } from 'sonner' export function SkillMatrix() { const { profile } = useAuth() const isAdmin = profile?.role === 'admin' + const currentUserId = profile?.id const { categories } = useCategories() const { skills } = useSkills() const { members } = useMembers() @@ -50,9 +54,34 @@ export function SkillMatrix() { toast.success('Niveau mis à jour') } + function exportCSV() { + const header = ['Compétence', ...visibleMembers.map((m) => m.full_name || m.email)].join(',') + const rows = filteredSkills.map((s) => { + const levelsRow = visibleMembers.map((m) => { + const key = `${m.id}-${s.id}` + return levels[key]?.level || '' + }) + return [`"${s.name}"`, ...levelsRow].join(',') + }) + const blob = new Blob(['\uFEFF' + header + '\n' + rows.join('\n')], { type: 'text/csv;charset=utf-8;' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') + a.href = url + a.download = 'matrice-competences.csv' + a.click() + URL.revokeObjectURL(url) + toast.success('Fichier CSV téléchargé') + } + return (