Add Telegram notifications for admin on user login
- 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
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user