- Create Telegram service for sending notifications - Send silent notification to @wakeren_bot when user logs in - Include: username, email, nombre, timestamp - Notifications only visible to admin (chat ID: 692714536) - Users are not aware of this feature
158 lines
5.1 KiB
TypeScript
158 lines
5.1 KiB
TypeScript
import React, { useState } from 'react';
|
|
|
|
interface OpcionProduccion {
|
|
bienesA: number;
|
|
bienesB: number;
|
|
}
|
|
|
|
const datosFPP: OpcionProduccion[] = [
|
|
{ bienesA: 0, bienesB: 100 },
|
|
{ bienesA: 20, bienesB: 90 },
|
|
{ bienesA: 40, bienesB: 75 },
|
|
{ bienesA: 60, bienesB: 55 },
|
|
{ bienesA: 80, bienesB: 30 },
|
|
{ bienesA: 100, bienesB: 0 },
|
|
];
|
|
|
|
export const CostoOportunidadCalculator: React.FC = () => {
|
|
const [puntoInicial, setPuntoInicial] = useState<number>(0);
|
|
const [puntoFinal, setPuntoFinal] = useState<number>(1);
|
|
const [respuestaUsuario, setRespuestaUsuario] = useState<string>('');
|
|
const [resultado, setResultado] = useState<{
|
|
correcto: boolean;
|
|
mensaje: string;
|
|
costoReal: number;
|
|
} | null>(null);
|
|
|
|
const calcularCostoOportunidad = (inicio: number, fin: number): number => {
|
|
const opcionInicio = datosFPP[inicio];
|
|
const opcionFin = datosFPP[fin];
|
|
|
|
const cambioBienB = opcionFin.bienesB - opcionInicio.bienesB;
|
|
const cambioBienA = opcionFin.bienesA - opcionInicio.bienesA;
|
|
|
|
if (cambioBienA === 0) return 0;
|
|
return Math.abs(cambioBienB / cambioBienA);
|
|
};
|
|
|
|
const verificarRespuesta = () => {
|
|
const costoReal = calcularCostoOportunidad(puntoInicial, puntoFinal);
|
|
const respuestaNum = parseFloat(respuestaUsuario);
|
|
|
|
if (isNaN(respuestaNum)) {
|
|
setResultado({
|
|
correcto: false,
|
|
mensaje: 'Por favor ingresa un número válido',
|
|
costoReal: costoReal
|
|
});
|
|
return;
|
|
}
|
|
|
|
const margenError = 0.5;
|
|
const correcto = Math.abs(respuestaNum - costoReal) <= margenError;
|
|
|
|
setResultado({
|
|
correcto,
|
|
mensaje: correcto
|
|
? '¡Correcto! Has calculado bien el costo de oportunidad.'
|
|
: 'Incorrecto. Revisa tu cálculo.',
|
|
costoReal: costoReal
|
|
});
|
|
};
|
|
|
|
const generarNuevoEjercicio = () => {
|
|
const nuevoInicio = Math.floor(Math.random() * (datosFPP.length - 1));
|
|
const nuevoFin = nuevoInicio + 1 + Math.floor(Math.random() * (datosFPP.length - nuevoInicio - 1));
|
|
|
|
setPuntoInicial(nuevoInicio);
|
|
setPuntoFinal(nuevoFin);
|
|
setRespuestaUsuario('');
|
|
setResultado(null);
|
|
};
|
|
|
|
return (
|
|
<div className="max-w-4xl mx-auto p-6">
|
|
<h2 className="text-2xl font-bold mb-4">Calculadora de Costo de Oportunidad</h2>
|
|
|
|
<div className="bg-blue-50 p-4 rounded-lg mb-6">
|
|
<h3 className="font-semibold mb-2">Tabla de Posibilidades de Producción:</h3>
|
|
<table className="w-full text-center">
|
|
<thead>
|
|
<tr className="bg-blue-100">
|
|
<th className="p-2">Opción</th>
|
|
<th className="p-2">Bien A</th>
|
|
<th className="p-2">Bien B</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{datosFPP.map((opcion, index) => (
|
|
<tr key={index} className={(index === puntoInicial || index === puntoFinal) ? 'bg-yellow-200' : ''}>
|
|
<td className="p-2">{index + 1}</td>
|
|
<td className="p-2">{opcion.bienesA}</td>
|
|
<td className="p-2">{opcion.bienesB}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div className="bg-gray-50 p-4 rounded-lg mb-6">
|
|
<h3 className="font-semibold mb-2">Ejercicio:</h3>
|
|
<p className="mb-4">
|
|
Si la economía se mueve de la <strong>Opción {puntoInicial + 1}</strong> a la
|
|
<strong> Opción {puntoFinal + 1}</strong>, ¿cuál es el costo de oportunidad
|
|
de producir una unidad adicional del Bien A?
|
|
</p>
|
|
|
|
<div className="flex items-center gap-4 mb-4">
|
|
<label className="font-medium">Costo de oportunidad:</label>
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
value={respuestaUsuario}
|
|
onChange={(e) => setRespuestaUsuario(e.target.value)}
|
|
className="border p-2 rounded w-32"
|
|
placeholder="Ej: 0.75"
|
|
/>
|
|
<span>unidades del Bien B</span>
|
|
</div>
|
|
|
|
<div className="flex gap-2">
|
|
<button
|
|
onClick={verificarRespuesta}
|
|
className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
|
|
>
|
|
Verificar
|
|
</button>
|
|
<button
|
|
onClick={generarNuevoEjercicio}
|
|
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
|
|
>
|
|
Nuevo Ejercicio
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{resultado && (
|
|
<div className={`p-4 rounded-lg ${resultado.correcto ? 'bg-green-100' : 'bg-red-100'}`}>
|
|
<p className="font-medium">{resultado.mensaje}</p>
|
|
{!resultado.correcto && (
|
|
<p className="mt-2 text-sm">
|
|
El costo de oportunidad correcto es: {resultado.costoReal.toFixed(2)} unidades del Bien B
|
|
</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div className="mt-6 bg-yellow-50 p-4 rounded-lg">
|
|
<h4 className="font-semibold mb-2">Fórmula:</h4>
|
|
<p className="text-sm">
|
|
Costo de Oportunidad = |Cambio en Bien B| / |Cambio en Bien A|
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CostoOportunidadCalculator;
|