add: añadir modal emergente para gestionar subescalas con cartas dentro de cada función.
This commit is contained in:
@@ -3,14 +3,13 @@ import Controls from '../membershipFunction/Controls';
|
|||||||
|
|
||||||
const COLORS = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6', '#d946ef', '#06b6d4', '#8b5cf6', '#f43f5e', '#6366f1'];
|
const COLORS = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6', '#d946ef', '#06b6d4', '#8b5cf6', '#f43f5e', '#6366f1'];
|
||||||
|
|
||||||
export default function Step2FuzzyModeling({
|
export default function Step2FuzzyModeling({baseScale, mfDefinitions, selectedTerm, setSelectedTerm, updateCurrentMf, handleFinalSubmit, onBack, subscales, onOpenSubscale}) {
|
||||||
baseScale, mfDefinitions, selectedTerm, setSelectedTerm, updateCurrentMf, handleFinalSubmit, onBack
|
|
||||||
}) {
|
|
||||||
const scaleKeys = Object.keys(baseScale);
|
const scaleKeys = Object.keys(baseScale);
|
||||||
const selectedColor = COLORS[scaleKeys.indexOf(selectedTerm) % COLORS.length] || '#2563eb';
|
const selectedColor = COLORS[scaleKeys.indexOf(selectedTerm) % COLORS.length] || '#2563eb';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full bg-white p-6 rounded-2xl shadow-sm border border-slate-200 animate-fade-in relative overflow-visible">
|
<div className="w-full bg-white p-6 rounded-2xl shadow-sm border border-slate-200 animate-fade-in relative overflow-visible">
|
||||||
|
|
||||||
<div className="flex justify-between items-center mb-6 border-b pb-3">
|
<div className="flex justify-between items-center mb-6 border-b pb-3">
|
||||||
<h2 className="text-xl font-bold text-slate-800">Paso 2: Modelar Conceptos Difusos</h2>
|
<h2 className="text-xl font-bold text-slate-800">Paso 2: Modelar Conceptos Difusos</h2>
|
||||||
<button onClick={onBack} className="text-slate-500 hover:text-blue-600 text-sm font-semibold underline">← Volver a las cartas</button>
|
<button onClick={onBack} className="text-slate-500 hover:text-blue-600 text-sm font-semibold underline">← Volver a las cartas</button>
|
||||||
@@ -28,9 +27,23 @@ export default function Step2FuzzyModeling({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Chart baseScale={baseScale} mfDefinitions={mfDefinitions} selectedTerm={selectedTerm} colors={COLORS} />
|
<Chart
|
||||||
|
baseScale={baseScale}
|
||||||
|
mfDefinitions={mfDefinitions}
|
||||||
|
selectedTerm={selectedTerm}
|
||||||
|
colors={COLORS}
|
||||||
|
/>
|
||||||
|
|
||||||
<Controls selectedTerm={selectedTerm} currentMf={mfDefinitions[selectedTerm]} selectedColor={selectedColor} baseScale={baseScale} mfDefinitions={mfDefinitions} updateCurrentMf={updateCurrentMf} />
|
<Controls
|
||||||
|
selectedTerm={selectedTerm}
|
||||||
|
currentMf={mfDefinitions[selectedTerm]}
|
||||||
|
selectedColor={selectedColor}
|
||||||
|
baseScale={baseScale}
|
||||||
|
mfDefinitions={mfDefinitions}
|
||||||
|
updateCurrentMf={updateCurrentMf}
|
||||||
|
subscales={subscales}
|
||||||
|
onOpenSubscale={onOpenSubscale}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="w-full mt-8 flex justify-center">
|
<div className="w-full mt-8 flex justify-center">
|
||||||
<button onClick={handleFinalSubmit} className="px-10 py-3 bg-slate-900 text-white text-lg font-bold rounded-xl shadow-md hover:bg-black hover:shadow-lg transition-all">
|
<button onClick={handleFinalSubmit} className="px-10 py-3 bg-slate-900 text-white text-lg font-bold rounded-xl shadow-md hover:bg-black hover:shadow-lg transition-all">
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import BlankCardsCounter from '../BlankCardsCounter';
|
||||||
|
|
||||||
|
export default function SubscaleModal({ onClose, onSave, targetInfo }) {
|
||||||
|
|
||||||
|
const [cardsCount, setCardsCount] = useState(targetInfo?.initialData?.cardsCount || 2);
|
||||||
|
const [blankCards, setBlankCards] = useState(targetInfo?.initialData?.blankCards || [0]);
|
||||||
|
|
||||||
|
const handleAddCard = () => {
|
||||||
|
setCardsCount(prev => prev + 1);
|
||||||
|
setBlankCards([...blankCards, 0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveCard = () => {
|
||||||
|
if (cardsCount <= 2) return;
|
||||||
|
setCardsCount(prev => prev - 1);
|
||||||
|
setBlankCards(blankCards.slice(0, -1));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBlankCardChange = (index, delta) => {
|
||||||
|
const newBlanks = [...blankCards];
|
||||||
|
if (newBlanks[index] + delta >= 0) {
|
||||||
|
newBlanks[index] += delta;
|
||||||
|
setBlankCards(newBlanks);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
onSave(targetInfo.term, targetInfo.side, { cardsCount, blankCards });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
onSave(targetInfo.term, targetInfo.side, null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-slate-900/40 backdrop-blur-sm animate-fade-in">
|
||||||
|
<div className="bg-white w-full max-w-5xl p-8 rounded-3xl shadow-2xl mx-4 flex flex-col">
|
||||||
|
|
||||||
|
<div className="flex justify-between items-center mb-6 border-b pb-4">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-2xl font-bold text-slate-800">Diseñar Subescala</h2>
|
||||||
|
<p className="text-slate-500 font-medium">
|
||||||
|
Ajustando pendiente <span className="text-blue-600 font-bold">{targetInfo.side === 'left' ? 'Izquierda (Ascendente)' : 'Derecha (Descendente)'}</span> del término <span className="text-blue-600 font-bold">"{targetInfo.term}"</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button onClick={onClose} className="w-10 h-10 bg-slate-100 hover:bg-slate-200 text-slate-600 rounded-full font-bold transition-colors">✕</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Tablero */}
|
||||||
|
<div className="w-full py-10 overflow-x-auto flex justify-start px-4">
|
||||||
|
<div className="flex flex-row items-start min-w-max relative">
|
||||||
|
{Array.from({ length: cardsCount }).map((_, index) => (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<div className="flex flex-col items-center mx-2 my-2 relative z-20">
|
||||||
|
<div className="relative w-32 h-40 bg-slate-50 border-2 border-slate-300 rounded-2xl shadow-sm flex flex-col items-center justify-center group">
|
||||||
|
{cardsCount > 2 && index === cardsCount - 1 && (
|
||||||
|
<button onClick={handleRemoveCard} className="absolute -top-3 -right-3 w-8 h-8 bg-white text-slate-400 rounded-full border border-slate-200 flex items-center justify-center font-bold hover:bg-red-500 hover:text-white transition-colors z-10 shadow-sm opacity-0 group-hover:opacity-100">×</button>
|
||||||
|
)}
|
||||||
|
<span className="text-4xl font-black text-slate-200">{index + 1}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{index < cardsCount - 1 && (
|
||||||
|
<BlankCardsCounter index={index} blankCardsCount={blankCards[index]} handleBlankCardChange={handleBlankCardChange} />
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<div className="mx-2 my-2 h-40 flex items-center">
|
||||||
|
<button onClick={handleAddCard} className="w-32 h-40 border-4 border-dashed border-slate-300 rounded-2xl flex flex-col items-center justify-center text-slate-400 font-bold hover:bg-blue-50 hover:border-blue-400 hover:text-blue-500 transition-colors">
|
||||||
|
<span className="text-3xl">+</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Botones */}
|
||||||
|
<div className="mt-8 flex justify-between items-center border-t pt-6">
|
||||||
|
<button onClick={handleDelete} className="px-6 py-3 rounded-xl font-bold text-red-500 hover:bg-red-50 transition-colors">
|
||||||
|
Borrar Subescala
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<button onClick={onClose} className="px-6 py-3 rounded-xl font-bold text-slate-600 hover:bg-slate-100 transition-colors">
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button onClick={handleSave} className="px-8 py-3 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-xl shadow-md transition-colors">
|
||||||
|
Guardar Subescala
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,21 +1,18 @@
|
|||||||
export default function Controls({ selectedTerm, currentMf, selectedColor, baseScale, mfDefinitions, updateCurrentMf }) {
|
export default function Controls({
|
||||||
|
selectedTerm, currentMf, selectedColor, baseScale, mfDefinitions, updateCurrentMf,
|
||||||
|
subscales, onOpenSubscale
|
||||||
|
}) {
|
||||||
if (!selectedTerm || !currentMf) return null;
|
if (!selectedTerm || !currentMf) return null;
|
||||||
|
|
||||||
const scaleKeys = Object.keys(baseScale);
|
const scaleKeys = Object.keys(baseScale);
|
||||||
const selectedIndex = scaleKeys.indexOf(selectedTerm);
|
const selectedIndex = scaleKeys.indexOf(selectedTerm);
|
||||||
|
|
||||||
let prevCoreEnd = 0, prevSupportEnd = 0, nextCoreStart = 1, nextSupportStart = 1;
|
let absoluteMin = 0, absoluteMax = 1;
|
||||||
|
if (selectedIndex > 0) absoluteMin = mfDefinitions[scaleKeys[selectedIndex - 1]].coreEnd;
|
||||||
|
if (selectedIndex < scaleKeys.length - 1) absoluteMax = mfDefinitions[scaleKeys[selectedIndex + 1]].coreStart;
|
||||||
|
|
||||||
if (selectedIndex > 0) {
|
const leftSubscale = subscales?.[selectedTerm]?.left;
|
||||||
const prevTerm = scaleKeys[selectedIndex - 1];
|
const rightSubscale = subscales?.[selectedTerm]?.right;
|
||||||
prevCoreEnd = mfDefinitions[prevTerm].coreEnd;
|
|
||||||
prevSupportEnd = mfDefinitions[prevTerm].supportEnd;
|
|
||||||
}
|
|
||||||
if (selectedIndex < scaleKeys.length - 1) {
|
|
||||||
const nextTerm = scaleKeys[selectedIndex + 1];
|
|
||||||
nextCoreStart = mfDefinitions[nextTerm].coreStart;
|
|
||||||
nextSupportStart = mfDefinitions[nextTerm].supportStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-md relative overflow-hidden">
|
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-md relative overflow-hidden">
|
||||||
@@ -24,34 +21,56 @@ export default function Controls({ selectedTerm, currentMf, selectedColor, baseS
|
|||||||
Ajustando: <span style={{ color: selectedColor }}>"{selectedTerm}"</span>
|
Ajustando: <span style={{ color: selectedColor }}>"{selectedTerm}"</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
<div className="space-y-4">
|
{/* Lado izquierdo (Pendiente ascendente) */}
|
||||||
|
<div className="space-y-4 bg-slate-50 p-4 rounded-xl border border-slate-100">
|
||||||
<div>
|
<div>
|
||||||
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
||||||
<span>Inicio del Núcleo</span><span style={{ color: selectedColor }}>{currentMf.coreStart.toFixed(3)}</span>
|
<span>Inicio del Soporte (Punto inferior)</span><span style={{ color: selectedColor }}>{currentMf.supportStart.toFixed(3)}</span>
|
||||||
</label>
|
</label>
|
||||||
<input type="range" min={prevSupportEnd} max={nextCoreStart} step="0.001" value={currentMf.coreStart} onChange={(e) => updateCurrentMf('coreStart', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor }} />
|
<input type="range" min={absoluteMin} max={absoluteMax} step="0.001" value={currentMf.supportStart} onChange={(e) => updateCurrentMf('supportStart', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor, opacity: 0.7 }} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
||||||
<span>Inicio del Soporte</span><span style={{ color: selectedColor }}>{currentMf.supportStart.toFixed(3)}</span>
|
<span>Inicio del Núcleo (Punto superior)</span><span style={{ color: selectedColor }}>{currentMf.coreStart.toFixed(3)}</span>
|
||||||
</label>
|
</label>
|
||||||
<input type="range" min={prevCoreEnd} max={nextCoreStart} step="0.001" value={currentMf.supportStart} onChange={(e) => updateCurrentMf('supportStart', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor, opacity: 0.7 }} />
|
<input type="range" min={absoluteMin} max={absoluteMax} step="0.001" value={currentMf.coreStart} onChange={(e) => updateCurrentMf('coreStart', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor }} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Botón subescala izquierda */}
|
||||||
|
<div className="pt-2 border-t border-slate-200 flex justify-end">
|
||||||
|
<button
|
||||||
|
onClick={() => onOpenSubscale(selectedTerm, 'left', leftSubscale)}
|
||||||
|
className={`text-sm font-bold px-4 py-2 rounded-lg transition-all border ${leftSubscale ? 'bg-blue-50 text-blue-700 border-blue-200' : 'bg-white text-slate-600 border-slate-200 hover:bg-slate-50'}`}
|
||||||
|
>
|
||||||
|
{leftSubscale ? `✎ Subescala (Cartas: ${leftSubscale.cardsCount})` : '+ Añadir Subescala'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
{/* Lado derecho (Pendiente descendente) */}
|
||||||
|
<div className="space-y-4 bg-slate-50 p-4 rounded-xl border border-slate-100">
|
||||||
<div>
|
<div>
|
||||||
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
||||||
<span>Fin del Núcleo</span><span style={{ color: selectedColor }}>{currentMf.coreEnd.toFixed(3)}</span>
|
<span>Fin del Núcleo (Punto superior)</span><span style={{ color: selectedColor }}>{currentMf.coreEnd.toFixed(3)}</span>
|
||||||
</label>
|
</label>
|
||||||
<input type="range" min={prevCoreEnd} max={nextSupportStart} step="0.001" value={currentMf.coreEnd} onChange={(e) => updateCurrentMf('coreEnd', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor }} />
|
<input type="range" min={absoluteMin} max={absoluteMax} step="0.001" value={currentMf.coreEnd} onChange={(e) => updateCurrentMf('coreEnd', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor }} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
<label className="flex justify-between text-xs font-bold text-slate-600 mb-1">
|
||||||
<span>Fin del Soporte</span><span style={{ color: selectedColor }}>{currentMf.supportEnd.toFixed(3)}</span>
|
<span>Fin del Soporte (Punto inferior)</span><span style={{ color: selectedColor }}>{currentMf.supportEnd.toFixed(3)}</span>
|
||||||
</label>
|
</label>
|
||||||
<input type="range" min={prevCoreEnd} max={nextCoreStart} step="0.001" value={currentMf.supportEnd} onChange={(e) => updateCurrentMf('supportEnd', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor, opacity: 0.7 }} />
|
<input type="range" min={absoluteMin} max={absoluteMax} step="0.001" value={currentMf.supportEnd} onChange={(e) => updateCurrentMf('supportEnd', e.target.value)} className="w-full cursor-pointer h-1.5" style={{ accentColor: selectedColor, opacity: 0.7 }} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Botón subescala derecha */}
|
||||||
|
<div className="pt-2 border-t border-slate-200 flex justify-end">
|
||||||
|
<button
|
||||||
|
onClick={() => onOpenSubscale(selectedTerm, 'right', rightSubscale)}
|
||||||
|
className={`text-sm font-bold px-4 py-2 rounded-lg transition-all border ${rightSubscale ? 'bg-blue-50 text-blue-700 border-blue-200' : 'bg-white text-slate-600 border-slate-200 hover:bg-slate-50'}`}
|
||||||
|
>
|
||||||
|
{rightSubscale ? `✎ Subescala (Cartas: ${rightSubscale.cardsCount})` : '+ Añadir Subescala'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import Step1BaseScale from '../components/editor/Step1BaseScale';
|
import Step1BaseScale from '../components/editor/Step1BaseScale';
|
||||||
import Step2FuzzyModeling from '../components/editor/Step2FuzzyModeling';
|
import Step2FuzzyModeling from '../components/editor/Step2FuzzyModeling';
|
||||||
|
import SubscaleModal from '../components/editor/SubscaleModal'; // <-- IMPORTAMOS EL MODAL
|
||||||
import { calculateValueFunction } from '../services/docService';
|
import { calculateValueFunction } from '../services/docService';
|
||||||
|
|
||||||
export default function DocEditor() {
|
export default function DocEditor() {
|
||||||
@@ -18,6 +19,11 @@ export default function DocEditor() {
|
|||||||
const [selectedTerm, setSelectedTerm] = useState(null);
|
const [selectedTerm, setSelectedTerm] = useState(null);
|
||||||
const [mfDefinitions, setMfDefinitions] = useState({});
|
const [mfDefinitions, setMfDefinitions] = useState({});
|
||||||
|
|
||||||
|
// ESTADOS: SUBESCALAS (FASE 2.5)
|
||||||
|
// Formato: { "regular": { left: { cardsCount: 3, blankCards: [1, 0] }, right: null }, "bueno": ... }
|
||||||
|
const [subscales, setSubscales] = useState({});
|
||||||
|
const [modalTarget, setModalTarget] = useState(null); // { term: 'regular', side: 'left', initialData: {...} }
|
||||||
|
|
||||||
// MANEJADORES: FASE 1
|
// MANEJADORES: FASE 1
|
||||||
const handleCriterionChange = (val) => { setCriterionName(val); if (errors.criterion) setErrors({ ...errors, criterion: false }); };
|
const handleCriterionChange = (val) => { setCriterionName(val); if (errors.criterion) setErrors({ ...errors, criterion: false }); };
|
||||||
const handleLevelChange = (index, newValue) => { const newLevels = [...levels]; newLevels[index] = newValue; setLevels(newLevels); if (errors.levels[index]) setErrors({ ...errors, levels: errors.levels.map((e, i) => i === index ? false : e) }); };
|
const handleLevelChange = (index, newValue) => { const newLevels = [...levels]; newLevels[index] = newValue; setLevels(newLevels); if (errors.levels[index]) setErrors({ ...errors, levels: errors.levels.map((e, i) => i === index ? false : e) }); };
|
||||||
@@ -36,11 +42,9 @@ export default function DocEditor() {
|
|||||||
try {
|
try {
|
||||||
const payloadBase = { criterion_name: criterionName.trim(), levels: levels.map(l => l.trim()), blank_cards: blankCards, references: { "0": 0, [(levels.length - 1).toString()]: 1 } };
|
const payloadBase = { criterion_name: criterionName.trim(), levels: levels.map(l => l.trim()), blank_cards: blankCards, references: { "0": 0, [(levels.length - 1).toString()]: 1 } };
|
||||||
const baseResult = await calculateValueFunction(payloadBase);
|
const baseResult = await calculateValueFunction(payloadBase);
|
||||||
|
|
||||||
setBaseScale(baseResult.values);
|
setBaseScale(baseResult.values);
|
||||||
const initialMfs = {};
|
const initialMfs = {};
|
||||||
Object.entries(baseResult.values).forEach(([name, value]) => { initialMfs[name] = { supportStart: value, coreStart: value, coreEnd: value, supportEnd: value }; });
|
Object.entries(baseResult.values).forEach(([name, value]) => { initialMfs[name] = { supportStart: value, coreStart: value, coreEnd: value, supportEnd: value }; });
|
||||||
|
|
||||||
setMfDefinitions(initialMfs);
|
setMfDefinitions(initialMfs);
|
||||||
setSelectedTerm(Object.keys(baseResult.values)[0]);
|
setSelectedTerm(Object.keys(baseResult.values)[0]);
|
||||||
setStep(2);
|
setStep(2);
|
||||||
@@ -51,7 +55,6 @@ export default function DocEditor() {
|
|||||||
const updateCurrentMf = (field, value) => {
|
const updateCurrentMf = (field, value) => {
|
||||||
if (!selectedTerm) return;
|
if (!selectedTerm) return;
|
||||||
let numValue = parseFloat(value);
|
let numValue = parseFloat(value);
|
||||||
|
|
||||||
setMfDefinitions(prev => {
|
setMfDefinitions(prev => {
|
||||||
const scaleKeys = Object.keys(baseScale);
|
const scaleKeys = Object.keys(baseScale);
|
||||||
const selectedIndex = scaleKeys.indexOf(selectedTerm);
|
const selectedIndex = scaleKeys.indexOf(selectedTerm);
|
||||||
@@ -72,7 +75,6 @@ export default function DocEditor() {
|
|||||||
if (field === 'coreStart' && numValue < prevSupportEnd) numValue = prevSupportEnd;
|
if (field === 'coreStart' && numValue < prevSupportEnd) numValue = prevSupportEnd;
|
||||||
if (field === 'coreEnd' && numValue > nextSupportStart) numValue = nextSupportStart;
|
if (field === 'coreEnd' && numValue > nextSupportStart) numValue = nextSupportStart;
|
||||||
if (field === 'supportEnd' && numValue > nextCoreStart) numValue = nextCoreStart;
|
if (field === 'supportEnd' && numValue > nextCoreStart) numValue = nextCoreStart;
|
||||||
|
|
||||||
if ((field === 'supportStart' || field === 'coreStart') && numValue > anchor) numValue = anchor;
|
if ((field === 'supportStart' || field === 'coreStart') && numValue > anchor) numValue = anchor;
|
||||||
if ((field === 'supportEnd' || field === 'coreEnd') && numValue < anchor) numValue = anchor;
|
if ((field === 'supportEnd' || field === 'coreEnd') && numValue < anchor) numValue = anchor;
|
||||||
|
|
||||||
@@ -95,14 +97,29 @@ export default function DocEditor() {
|
|||||||
if (current.coreEnd < current.coreStart) current.coreStart = current.coreEnd;
|
if (current.coreEnd < current.coreStart) current.coreStart = current.coreEnd;
|
||||||
if (current.coreStart < current.supportStart) current.supportStart = current.coreStart;
|
if (current.coreStart < current.supportStart) current.supportStart = current.coreStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { ...prev, [selectedTerm]: current };
|
return { ...prev, [selectedTerm]: current };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// MANEJADORES: SUBESCALAS
|
||||||
|
const handleOpenSubscale = (term, side, initialData) => {
|
||||||
|
setModalTarget({ term, side, initialData });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveSubscale = (term, side, data) => {
|
||||||
|
setSubscales(prev => ({
|
||||||
|
...prev,
|
||||||
|
[term]: {
|
||||||
|
...prev[term],
|
||||||
|
[side]: data
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
setModalTarget(null);
|
||||||
|
};
|
||||||
|
|
||||||
const handleFinalSubmit = () => {
|
const handleFinalSubmit = () => {
|
||||||
console.log("PAYLOAD DOC-MF:", { baseScale, mfDefinitions });
|
console.log("PAYLOAD DOC-MF COMPLETO:", { baseScale, mfDefinitions, subscales });
|
||||||
alert("¡Mira la consola! JSON preparado.");
|
alert("JSON en consola.");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -122,6 +139,17 @@ export default function DocEditor() {
|
|||||||
selectedTerm={selectedTerm} setSelectedTerm={setSelectedTerm}
|
selectedTerm={selectedTerm} setSelectedTerm={setSelectedTerm}
|
||||||
updateCurrentMf={updateCurrentMf} handleFinalSubmit={handleFinalSubmit}
|
updateCurrentMf={updateCurrentMf} handleFinalSubmit={handleFinalSubmit}
|
||||||
onBack={() => setStep(1)}
|
onBack={() => setStep(1)}
|
||||||
|
subscales={subscales}
|
||||||
|
onOpenSubscale={handleOpenSubscale}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{modalTarget && (
|
||||||
|
<SubscaleModal
|
||||||
|
key={`${modalTarget.term}-${modalTarget.side}`}
|
||||||
|
onClose={() => setModalTarget(null)}
|
||||||
|
onSave={handleSaveSubscale}
|
||||||
|
targetInfo={modalTarget}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user