137 lines
5.1 KiB
JavaScript
137 lines
5.1 KiB
JavaScript
// Rôle : fournit l'outil de planification d'équipements, sertissages, résumé et échange texte.
|
|
import { useMemo, useState } from "react";
|
|
import { moveItem, useGroupedReorder } from "../../../hooks/useGroupedReorder.js";
|
|
import { TextExchangeActions } from "./TextExchangeActions.jsx";
|
|
import { EQUIPMENT_ICONS } from "./equipmentPlannerOptions.js";
|
|
import { EquipmentItem } from "./EquipmentPlannerItem.jsx";
|
|
import { IconChoiceDropdown } from "./EquipmentPlannerPickers.jsx";
|
|
import { EquipmentPlannerSummary } from "./EquipmentPlannerSummary.jsx";
|
|
|
|
export function EquipmentPlannerModule({ toolboxId, moduleId, context, editing }) {
|
|
const data = context.normalizeEquipmentPlannerData(context.getModuleData(toolboxId, moduleId, { types: [], equipments: [] }));
|
|
const summary = useMemo(() => context.summarizeEquipmentPlannerData(data), [context, data]);
|
|
const textContent = context.moduleText?.equipmentPlanner || {};
|
|
const [equipmentIcon, setEquipmentIcon] = useState("helmet");
|
|
const [equipmentName, setEquipmentName] = useState("");
|
|
const {
|
|
itemReorder,
|
|
groupReorder,
|
|
getItemProps,
|
|
getGroupProps,
|
|
getGroupBoundaryProps,
|
|
isItemDragging,
|
|
isItemDropTarget,
|
|
isGroupDragging,
|
|
isGroupDropTarget,
|
|
isBoundaryDropTarget,
|
|
getDropPlacement,
|
|
shouldShowGroupBoundaries
|
|
} = useGroupedReorder({
|
|
namespace: `equipment-planner-${moduleId}`,
|
|
items: data.equipments,
|
|
getItemId: (equipment) => equipment.id,
|
|
onItemMove: (operation) => save({ ...data, equipments: moveItem(data.equipments, operation.sourceId, operation.targetId, operation.placement) })
|
|
});
|
|
const reorder = {
|
|
itemReorder,
|
|
groupReorder,
|
|
getItemProps,
|
|
getGroupProps,
|
|
getGroupBoundaryProps,
|
|
isItemDragging,
|
|
isItemDropTarget,
|
|
isGroupDragging,
|
|
isGroupDropTarget,
|
|
isBoundaryDropTarget,
|
|
getDropPlacement,
|
|
shouldShowGroupBoundaries
|
|
};
|
|
|
|
function save(nextData) {
|
|
context.setModuleData(toolboxId, moduleId, nextData, "equipmentPlanner");
|
|
}
|
|
|
|
function addEquipment(event) {
|
|
event.preventDefault();
|
|
const cleanName = equipmentName.trim();
|
|
if (!cleanName) return;
|
|
const type = data.types[0] || { id: context.uid("equipmentType"), title: "Équipements", icon: "shield", collapsed: false };
|
|
const nextData = {
|
|
...data,
|
|
types: data.types.length ? data.types : [type],
|
|
typeOrder: data.typeOrder.length ? data.typeOrder : [type.id],
|
|
equipments: [
|
|
...data.equipments,
|
|
{
|
|
id: context.uid("equipment"),
|
|
typeId: type.id,
|
|
name: cleanName,
|
|
icon: equipmentIcon,
|
|
active: true,
|
|
obtain: "",
|
|
characteristics: [],
|
|
socketItems: [],
|
|
socketLinks: [],
|
|
materials: [],
|
|
categoryOrder: [],
|
|
collapsedCategories: []
|
|
}
|
|
]
|
|
};
|
|
save(nextData);
|
|
setEquipmentName("");
|
|
}
|
|
|
|
function updateEquipment(equipmentId, updater) {
|
|
save({ ...data, equipments: data.equipments.map((equipment) => equipment.id === equipmentId ? updater(equipment) : equipment) });
|
|
}
|
|
|
|
function deleteEquipment(equipmentId) {
|
|
const nextEquipments = data.equipments.filter((equipment) => equipment.id !== equipmentId);
|
|
const usedTypeIds = new Set(nextEquipments.map((equipment) => equipment.typeId));
|
|
save({
|
|
...data,
|
|
equipments: nextEquipments,
|
|
types: data.types.filter((type) => usedTypeIds.has(type.id)),
|
|
typeOrder: data.typeOrder.filter((typeId) => usedTypeIds.has(typeId))
|
|
});
|
|
}
|
|
|
|
return (
|
|
<div className="equipment-planner-module">
|
|
{editing && (
|
|
<div className="module-add-panel">
|
|
<form className="inline-form equipment-planner-add-form" onSubmit={addEquipment}>
|
|
<IconChoiceDropdown
|
|
className="equipment-planner-equipment-icon-picker"
|
|
label={textContent.equipmentIconLabel || "Type"}
|
|
value={equipmentIcon}
|
|
options={EQUIPMENT_ICONS}
|
|
onChange={setEquipmentIcon}
|
|
/>
|
|
<input value={equipmentName} onChange={(event) => setEquipmentName(event.target.value)} placeholder={textContent.equipmentPlaceholder || "Nouvel équipement"} />
|
|
<button className="primary">{textContent.addEquipmentButton || "Ajouter"}</button>
|
|
</form>
|
|
<TextExchangeActions type="equipmentPlanner" data={data} context={context} textContent={textContent} onImport={(nextData) => save(nextData)} />
|
|
</div>
|
|
)}
|
|
|
|
<EquipmentPlannerSummary summary={summary} textContent={textContent} />
|
|
|
|
<ul className="equipment-planner-list">
|
|
{data.equipments.length ? data.equipments.map((equipment) => (
|
|
<EquipmentItem
|
|
key={equipment.id}
|
|
equipment={equipment}
|
|
reorder={reorder}
|
|
textContent={textContent}
|
|
onUpdate={(updater) => updateEquipment(equipment.id, updater)}
|
|
onDelete={() => deleteEquipment(equipment.id)}
|
|
/>
|
|
)) : (
|
|
<li className="equipment-planner-empty">{textContent.emptyEquipments || "Aucun équipement planifié."}</li>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
);
|
|
}
|