// Rôle : rend les sous-composants d'édition et de prévisualisation de l'arbre d'objectifs. import { useState } from "react"; import { CompactDropdown } from "../../../components/CompactDropdown.jsx"; import { Icon } from "../../../components/Icon.jsx"; import { MixTagsInput } from "../../../components/MixTagsInput.jsx"; import { Tooltip } from "../../../components/Tooltip.jsx"; import { GOAL_TREE_ICON_NAMES, formatGoalTreeNumber, getGoalTreeChildren, getGoalTreeDescendantIds, getGoalTreeParentIds } from "./goalTreeUtils.js"; import { BASE_TOKEN, getEffectiveGoalTreeProgressMode, getGoalTreeNodeIcon, getGoalTreeNodeIconColor, getGoalTreeNodeTooltip, isSingleValueGoalTreeNode } from "./goalTreeDisplay.js"; export function GoalTreePrerequisitePicker({ nodes, node, textContent, onToggle }) { const parentIds = new Set(getGoalTreeParentIds(node)); const blockedIds = new Set([node.id, ...getGoalTreeDescendantIds(nodes, node.id)]); const primaryParent = nodes.find((candidate) => candidate.id === node.parentId); const options = nodes.filter((candidate) => !blockedIds.has(candidate.id) && candidate.id !== node.parentId); if (!primaryParent && !options.length) return null; return (
{textContent.prerequisitesSectionTitle || "Prérequis supplémentaires"}
{primaryParent && ( )} {options.map((candidate) => ( ))}
); } export function GoalTreeBranch({ nodes, parentId, selectedNodeId, editing, reorder, textContent, onSelect, onAdd, onAddContentItem, onSetStepLeafQuantity, onSetStepChildrenCompletion, onUpdateNodeItem, onEditNode, onToggleBranch, onDeleteNode }) { const children = getGoalTreeChildren(nodes, parentId); if (!children.length) return null; return ( ); } export function GoalTreeTitleInput({ value, onChange }) { const [draft, setDraft] = useState(value || ""); return ( { const title = event.target.value; setDraft(title); onChange(title); }} /> ); } export function GoalTreeFormulaInput({ value, onChange, hasParent, textContent, placeholder, title, className = "", "aria-label": ariaLabel }) { const normalizedValue = String(value ?? ""); if (!hasParent) { return onChange(event.target.value.replaceAll(",", "."))} placeholder={placeholder} title={title} value={normalizedValue} />; } return ( onChange(nextValue.replaceAll(",", "."))} placeholder={placeholder} title={title} tokens={[{ value: BASE_TOKEN, label: textContent.baseTokenLabel || "Valeur du parent" }]} value={normalizedValue} /> ); } export function GoalTreeContentEditor({ node, textContent, onAdd, onUpdate, onDelete }) { return (
{textContent.contentSectionTitle || "Contenu"}
{(node.items || []).map((item) => (
onUpdate(item.id, (current) => ({ ...current, label: event.target.value }))} aria-label={textContent.itemLabelLabel || "Libellé"} /> {node.kind === "checklist" && ( onUpdate(item.id, (current) => ({ ...current, formula: value.replaceAll(",", ".") }))} value={item.formula || "1"} placeholder={textContent.itemTotalPlaceholder || "base"} textContent={textContent} title={textContent.itemTotalHelp || "Saisissez un nombre ou une formule avec base pour référencer la cible du parent."} /> )}
))}
); } function GoalTreeChecklistInlineControl({ item, textContent, onUpdate }) { const target = Math.max(1, item.qtyTarget || 1); const current = Math.min(Math.max(0, item.qtyCurrent || 0), target); if (target <= 1) { return = 1} onChange={(event) => onUpdate((entry) => ({ ...entry, qtyCurrent: event.target.checked ? 1 : 0 }))} aria-label={textContent.itemCheckedLabel || "État"} />; } return ( {formatGoalTreeNumber(current)} / {formatGoalTreeNumber(target)} ); } function GoalTreeStepLeafControl({ node, textContent, onChange }) { const target = Math.max(1, node.computedQtyTarget || node.qtyTarget || 1); const current = Math.min(Math.max(0, node.qtyCurrent || 0), target); if (target <= 1) { return = 1} onChange={(event) => onChange(event.target.checked ? 1 : 0)} aria-label={textContent.itemCheckedLabel || "État"} />; } return ( {formatGoalTreeNumber(current)} / {formatGoalTreeNumber(target)} ); } function GoalTreeNodeContentPreview({ node, editing, textContent, onAddContentItem, onUpdateItem }) { const items = node.items || []; return ( {items.map((item) => ( {node.kind === "checklist" && onUpdateItem(item.id, updater)} />} {item.label} ))} {editing && ( )} ); } export function GoalTreeIconPicker({ label, value, textContent, onChange }) { return (
{label} ( )} > {({ close }) => ( <> {GOAL_TREE_ICON_NAMES.map((icon) => ( ))} )}
); }