Implement collapse functionality in EvaluationDetailPage and DimensionCard components, allowing users to collapse all dimension cards simultaneously for improved usability and organization.
This commit is contained in:
@@ -54,6 +54,7 @@ export default function EvaluationDetailPage() {
|
|||||||
const [templates, setTemplates] = useState<{ id: string; name: string }[]>([]);
|
const [templates, setTemplates] = useState<{ id: string; name: string }[]>([]);
|
||||||
const [exportOpen, setExportOpen] = useState(false);
|
const [exportOpen, setExportOpen] = useState(false);
|
||||||
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
|
||||||
|
const [collapseAllTrigger, setCollapseAllTrigger] = useState(0);
|
||||||
|
|
||||||
const fetchEval = useCallback(() => {
|
const fetchEval = useCallback(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -214,16 +215,22 @@ export default function EvaluationDetailPage() {
|
|||||||
const dimensions = evaluation.template?.dimensions ?? [];
|
const dimensions = evaluation.template?.dimensions ?? [];
|
||||||
const dimensionScores = evaluation.dimensionScores ?? [];
|
const dimensionScores = evaluation.dimensionScores ?? [];
|
||||||
const scoreMap = new Map(dimensionScores.map((ds) => [ds.dimensionId, ds]));
|
const scoreMap = new Map(dimensionScores.map((ds) => [ds.dimensionId, ds]));
|
||||||
const radarData = dimensionScores
|
const radarData = dimensions
|
||||||
.filter((ds) => ds.score != null)
|
.filter((dim) => !(dim.title ?? "").startsWith("[Optionnel]"))
|
||||||
.map((ds) => {
|
.map((dim) => {
|
||||||
const title = ds.dimension?.title ?? "";
|
const ds = scoreMap.get(dim.id);
|
||||||
|
const score = ds?.score;
|
||||||
|
if (score == null) return null;
|
||||||
|
const title = dim.title ?? "";
|
||||||
|
const s = Number(score);
|
||||||
|
if (Number.isNaN(s) || s < 0 || s > 5) return null;
|
||||||
return {
|
return {
|
||||||
dimension: title.length > 12 ? title.slice(0, 12) + "…" : title,
|
dimension: title.length > 12 ? title.slice(0, 12) + "…" : title,
|
||||||
score: ds.score ?? 0,
|
score: s,
|
||||||
fullMark: 5,
|
fullMark: 5,
|
||||||
};
|
};
|
||||||
});
|
})
|
||||||
|
.filter((d): d is { dimension: string; score: number; fullMark: number } => d != null);
|
||||||
const avgScore = computeAverageScore(dimensionScores);
|
const avgScore = computeAverageScore(dimensionScores);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -275,7 +282,16 @@ export default function EvaluationDetailPage() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<h2 className="mb-3 font-mono text-xs text-zinc-600 dark:text-zinc-500">Dimensions</h2>
|
<div className="mb-3 flex items-center justify-between gap-2">
|
||||||
|
<h2 className="font-mono text-xs text-zinc-600 dark:text-zinc-500">Dimensions</h2>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setCollapseAllTrigger((c) => c + 1)}
|
||||||
|
className="font-mono text-xs text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300"
|
||||||
|
>
|
||||||
|
tout fermer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<nav className="mb-4 flex flex-wrap gap-1.5">
|
<nav className="mb-4 flex flex-wrap gap-1.5">
|
||||||
{dimensions.map((dim, i) => {
|
{dimensions.map((dim, i) => {
|
||||||
const ds = scoreMap.get(dim.id);
|
const ds = scoreMap.get(dim.id);
|
||||||
@@ -304,6 +320,7 @@ export default function EvaluationDetailPage() {
|
|||||||
evaluationId={id}
|
evaluationId={id}
|
||||||
score={scoreMap.get(dim.id) ?? null}
|
score={scoreMap.get(dim.id) ?? null}
|
||||||
onScoreChange={handleScoreChange}
|
onScoreChange={handleScoreChange}
|
||||||
|
collapseAllTrigger={collapseAllTrigger}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ interface DimensionCardProps {
|
|||||||
index: number;
|
index: number;
|
||||||
evaluationId?: string;
|
evaluationId?: string;
|
||||||
onScoreChange: (dimensionId: string, data: Partial<DimensionScore>) => void;
|
onScoreChange: (dimensionId: string, data: Partial<DimensionScore>) => void;
|
||||||
|
/** Increment to collapse this card (e.g. from "Tout fermer" button) */
|
||||||
|
collapseAllTrigger?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRubric(rubric: string): string[] {
|
function parseRubric(rubric: string): string[] {
|
||||||
@@ -76,7 +78,7 @@ function parseQuestions(s: string | null | undefined): string[] {
|
|||||||
const inputClass =
|
const inputClass =
|
||||||
"w-full rounded border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-700/80 px-2.5 py-1.5 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 dark:placeholder-zinc-500 focus:border-cyan-500 focus:ring-1 focus:ring-cyan-500/30";
|
"w-full rounded border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-700/80 px-2.5 py-1.5 text-sm text-zinc-900 dark:text-zinc-100 placeholder-zinc-400 dark:placeholder-zinc-500 focus:border-cyan-500 focus:ring-1 focus:ring-cyan-500/30";
|
||||||
|
|
||||||
export function DimensionCard({ dimension, score, index, evaluationId, onScoreChange }: DimensionCardProps) {
|
export function DimensionCard({ dimension, score, index, evaluationId, onScoreChange, collapseAllTrigger }: DimensionCardProps) {
|
||||||
const [notes, setNotes] = useState(score?.candidateNotes ?? "");
|
const [notes, setNotes] = useState(score?.candidateNotes ?? "");
|
||||||
const hasQuestions = parseQuestions(dimension.suggestedQuestions).length > 0;
|
const hasQuestions = parseQuestions(dimension.suggestedQuestions).length > 0;
|
||||||
const [expanded, setExpanded] = useState(hasQuestions);
|
const [expanded, setExpanded] = useState(hasQuestions);
|
||||||
@@ -88,6 +90,13 @@ export function DimensionCard({ dimension, score, index, evaluationId, onScoreCh
|
|||||||
}
|
}
|
||||||
}, [evaluationId, dimension.id]);
|
}, [evaluationId, dimension.id]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (collapseAllTrigger != null && collapseAllTrigger > 0) {
|
||||||
|
setExpanded(false);
|
||||||
|
if (evaluationId) setStoredExpanded(evaluationId, dimension.id, false);
|
||||||
|
}
|
||||||
|
}, [collapseAllTrigger, evaluationId, dimension.id]);
|
||||||
|
|
||||||
const toggleExpanded = () => {
|
const toggleExpanded = () => {
|
||||||
setExpanded((e) => {
|
setExpanded((e) => {
|
||||||
const next = !e;
|
const next = !e;
|
||||||
|
|||||||
Reference in New Issue
Block a user