diff --git a/frontend/index.html b/frontend/index.html
index f94d687..609e6e7 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -4,7 +4,7 @@
-
frontend
+ Deck of Cards
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 292034c..0545d76 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,243 +1,9 @@
-import { useState } from 'react';
-import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
-import { calculateValueFunction } from './services/docService';
+import BasicMode from './pages/BasicMode';
function App() {
-
- const [criterionName, setCriterionName] = useState('');
- const [levels, setLevels] = useState(['', '', '']);
- const [blankCards, setBlankCards] = useState([0, 0]);
-
- const [isLoading, setIsLoading] = useState(false);
- const [result, setResult] = useState(null);
-
- const handleCalculate = async () => {
- setIsLoading(true);
- setResult(null);
-
- const firstIndex = "0";
- const lastIndex = (levels.length - 1).toString();
-
- const currentReferences = {
- [firstIndex]: 0,
- [lastIndex]: 1
- };
-
- const payload = {
- criterion_name: criterionName || "Criterio sin nombre",
- levels: levels,
- blank_cards: blankCards,
- references: currentReferences
- };
-
- try {
- const data = await calculateValueFunction(payload);
- setResult(data);
- } catch (error) {
- alert("No se ha podido conectar con el backend: " + error);
- } finally {
- setIsLoading(false);
- }
- };
-
-
- const handleLevelChange = (index, newValue) => {
- const newLevels = [...levels];
- newLevels[index] = newValue;
- setLevels(newLevels);
- };
-
- const handleAddLevel = () => {
- setLevels([...levels, '']);
- setBlankCards([...blankCards, 0]);
- };
-
- const handleRemoveLevel = (indexToRemove) => {
- if (levels.length <= 2) return;
- const newLevels = levels.filter((_, index) => index !== indexToRemove);
- const blankIndexToRemove = indexToRemove === 0 ? 0 : indexToRemove - 1;
- const newBlankCards = blankCards.filter((_, index) => index !== blankIndexToRemove);
- setLevels(newLevels);
- setBlankCards(newBlankCards);
- };
-
- const handleBlankCardChange = (index, delta) => {
- const newBlankCards = [...blankCards];
- const newValue = newBlankCards[index] + delta;
- if (newValue >= 0) {
- newBlankCards[index] = newValue;
- setBlankCards(newBlankCards);
- }
- };
-
return (
-
- {/* TÍTULO */}
-
-
- setCriterionName(e.target.value)}
- className="w-full text-3xl font-bold p-2 text-center text-slate-700 border-b-2 border-transparent hover:border-slate-200 focus:border-blue-500 outline-none transition-colors"
- />
-
-
- {/* TIMELINE VERTICAL */}
-
- {levels.map((level, index) => (
-
-
- {/* CARTA DE NIVEL (etiqueta) */}
-
-
- {/* Botón Eliminar */}
- {levels.length > 2 && (
-
- )}
-
- {/* Detalles tipo naipe */}
-
- {index + 1}
-
-
- {index + 1}
-
-
- handleLevelChange(index, e.target.value)}
- className="w-4/5 text-center text-2xl font-bold text-slate-700 bg-transparent border-b-2 border-dashed border-slate-300 focus:border-blue-500 outline-none pb-1"
- />
-
-
- {/* CONECTOR Y CARTAS BLANCAS */}
- {index < levels.length - 1 && (
-
-
-
-
- Blancas:
-
-
- {blankCards[index]}
-
-
-
-
- {blankCards[index] > 0 && (
-
- {Array.from({ length: blankCards[index] }).map((_, i) => (
-
- ))}
-
- )}
-
-
-
- )}
-
- ))}
-
- {/* BOTÓN AÑADIR */}
-
-
-
-
-
-
- {/* BOTÓN DE CALCULAR */}
-
-
-
-
- {/* GRÁFICA */}
- {result && (
-
-
- Función de Valor: {result.criterion_name}
-
-
-
-
- ({
- nombre: label,
- valor: value
- }))}
- margin={{ top: 20, right: 30, left: 20, bottom: 20 }}
- >
-
-
-
-
-
-
- [value.toFixed(4), 'Valor DoC']}
- labelStyle={{ fontWeight: 'bold', color: '#1e293b', marginBottom: '4px' }}
- />
-
-
-
-
-
-
- )}
-
+
);
}
diff --git a/frontend/src/components/AddLevelButton.jsx b/frontend/src/components/AddLevelButton.jsx
new file mode 100644
index 0000000..1d39d4e
--- /dev/null
+++ b/frontend/src/components/AddLevelButton.jsx
@@ -0,0 +1,13 @@
+export default function AddLevelButton({ handleAddLevel }) {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/components/BlankCardsCounter.jsx b/frontend/src/components/BlankCardsCounter.jsx
index e69de29..2cabe8d 100644
--- a/frontend/src/components/BlankCardsCounter.jsx
+++ b/frontend/src/components/BlankCardsCounter.jsx
@@ -0,0 +1,36 @@
+export default function BlankCardsCounter({ index, blankCardsCount, handleBlankCardChange }) {
+ return (
+
+
+
+
+ Blancas:
+
+
+ {blankCardsCount}
+
+
+
+
+ {blankCardsCount > 0 && (
+
+ {Array.from({ length: blankCardsCount }).map((_, i) => (
+
+ ))}
+
+ )}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/components/CardEditor.jsx b/frontend/src/components/CardEditor.jsx
index e69de29..77c0c73 100644
--- a/frontend/src/components/CardEditor.jsx
+++ b/frontend/src/components/CardEditor.jsx
@@ -0,0 +1,33 @@
+export default function CardEditor({ index, level, handleLevelChange, handleRemoveLevel, totalLevels }) {
+ return (
+
+
+ {/* Botón Eliminar */}
+ {totalLevels > 2 && (
+
+ )}
+
+ {/* Detalles tipo naipe */}
+
+ {index + 1}
+
+
+ {index + 1}
+
+
+ handleLevelChange(index, e.target.value)}
+ className="w-4/5 text-center text-2xl font-bold text-slate-700 bg-transparent border-b-2 border-dashed border-slate-300 focus:border-blue-500 outline-none pb-1"
+ />
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/components/CriterionInput.jsx b/frontend/src/components/CriterionInput.jsx
new file mode 100644
index 0000000..300c2de
--- /dev/null
+++ b/frontend/src/components/CriterionInput.jsx
@@ -0,0 +1,16 @@
+export default function CriterionInput({ criterionName, setCriterionName }) {
+ return (
+
+
+ setCriterionName(e.target.value)}
+ className="w-full text-3xl font-bold p-2 text-center text-slate-700 border-b-2 border-transparent hover:border-slate-200 focus:border-blue-500 outline-none transition-colors"
+ />
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/components/ValueFunctionChart.jsx b/frontend/src/components/ValueFunctionChart.jsx
index e69de29..e496d46 100644
--- a/frontend/src/components/ValueFunctionChart.jsx
+++ b/frontend/src/components/ValueFunctionChart.jsx
@@ -0,0 +1,43 @@
+import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
+
+export default function ValueFunctionChart({ result }) {
+ if (!result) return null;
+
+ return (
+
+
+ Función de Valor: {result.criterion_name}
+
+
+
+
+ ({
+ nombre: label,
+ valor: value
+ }))}
+ margin={{ top: 20, right: 30, left: 20, bottom: 20 }}
+ >
+
+
+
+ [value.toFixed(4), 'Valor DoC']}
+ labelStyle={{ fontWeight: 'bold', color: '#1e293b', marginBottom: '4px' }}
+ />
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/pages/BasicMode.jsx b/frontend/src/pages/BasicMode.jsx
index e69de29..d5c7976 100644
--- a/frontend/src/pages/BasicMode.jsx
+++ b/frontend/src/pages/BasicMode.jsx
@@ -0,0 +1,124 @@
+import { useState } from 'react';
+import CriterionInput from '../components/CriterionInput';
+import CardEditor from '../components/CardEditor';
+import BlankCardsCounter from '../components/BlankCardsCounter';
+import AddLevelButton from '../components/AddLevelButton';
+import ValueFunctionChart from '../components/ValueFunctionChart';
+import { calculateValueFunction } from '../services/docService';
+
+export default function BasicMode() {
+ const [criterionName, setCriterionName] = useState('');
+ const [levels, setLevels] = useState(['', '', '']);
+ const [blankCards, setBlankCards] = useState([0, 0]);
+
+ const [isLoading, setIsLoading] = useState(false);
+ const [result, setResult] = useState(null);
+
+ const handleCalculate = async () => {
+ setIsLoading(true);
+ setResult(null);
+
+ const firstIndex = "0";
+ const lastIndex = (levels.length - 1).toString();
+
+ const currentReferences = {
+ [firstIndex]: 0,
+ [lastIndex]: 1
+ };
+
+ const payload = {
+ criterion_name: criterionName || "Criterio sin nombre",
+ levels: levels,
+ blank_cards: blankCards,
+ references: currentReferences
+ };
+
+ try {
+ const data = await calculateValueFunction(payload);
+ setResult(data);
+ } catch (error) {
+ alert("No se ha podido conectar con el backend: " + error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const handleLevelChange = (index, newValue) => {
+ const newLevels = [...levels];
+ newLevels[index] = newValue;
+ setLevels(newLevels);
+ };
+
+ const handleAddLevel = () => {
+ setLevels([...levels, '']);
+ setBlankCards([...blankCards, 0]);
+ };
+
+ const handleRemoveLevel = (indexToRemove) => {
+ if (levels.length <= 2) return;
+ const newLevels = levels.filter((_, index) => index !== indexToRemove);
+ const blankIndexToRemove = indexToRemove === 0 ? 0 : indexToRemove - 1;
+ const newBlankCards = blankCards.filter((_, index) => index !== blankIndexToRemove);
+ setLevels(newLevels);
+ setBlankCards(newBlankCards);
+ };
+
+ const handleBlankCardChange = (index, delta) => {
+ const newBlankCards = [...blankCards];
+ const newValue = newBlankCards[index] + delta;
+ if (newValue >= 0) {
+ newBlankCards[index] = newValue;
+ setBlankCards(newBlankCards);
+ }
+ };
+
+ return (
+
+
+
+
+
+ {levels.map((level, index) => (
+
+
+
+
+ {index < levels.length - 1 && (
+
+ )}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+);
+}
\ No newline at end of file