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,197 @@
|
||||
import { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Card } from '../../ui/Card';
|
||||
import { Button } from '../../ui/Button';
|
||||
import { CheckCircle, XCircle } from 'lucide-react';
|
||||
|
||||
interface EjercicioProps {
|
||||
ejercicioId: string;
|
||||
onComplete?: (puntuacion: number) => void;
|
||||
}
|
||||
|
||||
const PREGUNTAS = [
|
||||
{
|
||||
id: 1,
|
||||
pregunta: "¿Qué es la economía?",
|
||||
opciones: [
|
||||
"Ciencia social que estudia cómo se asignan recursos escasos para satisfacer necesidades ilimitadas",
|
||||
"Estudio exclusivo del dinero y los bancos",
|
||||
"Análisis únicamente de empresas grandes",
|
||||
"Gestión de presupuestos familiares"
|
||||
],
|
||||
correcta: 0,
|
||||
explicacion: "La economía es una ciencia social que estudia la asignación de recursos escasos para satisfacer necesidades ilimitadas."
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
pregunta: "¿Cuál es la diferencia entre microeconomía y macroeconomía?",
|
||||
opciones: [
|
||||
"La micro estudia individuos y empresas; la macro estudia la economía como un todo",
|
||||
"La micro es más difícil que la macro",
|
||||
"La micro estudia solo bancos; la macro estudia gobiernos",
|
||||
"No hay diferencia, son lo mismo"
|
||||
],
|
||||
correcta: 0,
|
||||
explicacion: "La microeconomía estudia el comportamiento de individuos y empresas, mientras que la macroeconomía analiza la economía en su conjunto (PIB, inflación, desempleo)."
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
pregunta: "¿Qué es el problema económico fundamental?",
|
||||
opciones: [
|
||||
"La escasez de recursos frente a necesidades ilimitadas",
|
||||
"La falta de dinero en los bancos",
|
||||
"El desempleo elevado",
|
||||
"La inflación alta"
|
||||
],
|
||||
correcta: 0,
|
||||
explicacion: "El problema económico fundamental es la escasez: los recursos son limitados pero las necesidades humanas son ilimitadas."
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
pregunta: "¿Qué estudia la economía positiva?",
|
||||
opciones: [
|
||||
"Lo que es (hechos y descripciones)",
|
||||
"Lo que debería ser (valores y juicios)",
|
||||
"Solo matemáticas económicas",
|
||||
"Únicamente historia económica"
|
||||
],
|
||||
correcta: 0,
|
||||
explicacion: "La economía positiva describe y explica hechos objetivos ('lo que es'), sin hacer juicios de valor."
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
pregunta: "Complete: La economía normativa se refiere a...",
|
||||
opciones: [
|
||||
"Juicios de valor sobre lo que debería ser",
|
||||
"Datos estadísticos objetivos",
|
||||
"Teorías matemáticas puras",
|
||||
"Hechos históricos verificables"
|
||||
],
|
||||
correcta: 0,
|
||||
explicacion: "La economía normativa hace juicios de valor y prescripciones sobre lo que debería ser ('deberíamos aumentar los impuestos')."
|
||||
}
|
||||
];
|
||||
|
||||
export function DefinicionEconomiaQuiz({ ejercicioId: _ejercicioId, onComplete }: EjercicioProps) {
|
||||
const [preguntaActual, setPreguntaActual] = useState(0);
|
||||
const [respuestas, setRespuestas] = useState<number[]>([]);
|
||||
const [mostrarResultado, setMostrarResultado] = useState(false);
|
||||
const [completado, setCompletado] = useState(false);
|
||||
|
||||
const pregunta = PREGUNTAS[preguntaActual];
|
||||
const esUltima = preguntaActual === PREGUNTAS.length - 1;
|
||||
|
||||
const handleRespuesta = (index: number) => {
|
||||
const nuevasRespuestas = [...respuestas, index];
|
||||
setRespuestas(nuevasRespuestas);
|
||||
|
||||
if (esUltima) {
|
||||
// Calcular puntuación
|
||||
const correctas = nuevasRespuestas.filter((r, i) => r === PREGUNTAS[i].correcta).length;
|
||||
const puntuacion = Math.round((correctas / PREGUNTAS.length) * 100);
|
||||
setCompletado(true);
|
||||
onComplete?.(puntuacion);
|
||||
} else {
|
||||
setMostrarResultado(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSiguiente = () => {
|
||||
setPreguntaActual(prev => prev + 1);
|
||||
setMostrarResultado(false);
|
||||
};
|
||||
|
||||
const esCorrecta = respuestas[preguntaActual] === pregunta.correcta;
|
||||
|
||||
if (completado) {
|
||||
const correctas = respuestas.filter((r, i) => r === PREGUNTAS[i].correcta).length;
|
||||
const puntuacion = Math.round((correctas / PREGUNTAS.length) * 100);
|
||||
|
||||
return (
|
||||
<Card className="w-full max-w-2xl mx-auto text-center p-8">
|
||||
<motion.div
|
||||
initial={{ scale: 0 }}
|
||||
animate={{ scale: 1 }}
|
||||
className="mb-6"
|
||||
>
|
||||
<div className="w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mx-auto">
|
||||
<CheckCircle className="w-10 h-10 text-green-600" />
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<h3 className="text-2xl font-bold text-gray-900 mb-2">¡Quiz Completado!</h3>
|
||||
<p className="text-gray-600 mb-6">
|
||||
Respondiste {correctas} de {PREGUNTAS.length} preguntas correctamente
|
||||
</p>
|
||||
|
||||
<div className="text-5xl font-bold text-blue-600 mb-2">{puntuacion}</div>
|
||||
<p className="text-gray-500">puntos</p>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="w-full max-w-2xl mx-auto">
|
||||
<div className="p-6">
|
||||
{/* Progress */}
|
||||
<div className="mb-6">
|
||||
<div className="flex justify-between text-sm text-gray-500 mb-2">
|
||||
<span>Pregunta {preguntaActual + 1} de {PREGUNTAS.length}</span>
|
||||
<span>{Math.round(((preguntaActual) / PREGUNTAS.length) * 100)}%</span>
|
||||
</div>
|
||||
<div className="w-full bg-gray-200 rounded-full h-2">
|
||||
<motion.div
|
||||
className="bg-blue-500 h-2 rounded-full"
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${((preguntaActual) / PREGUNTAS.length) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pregunta */}
|
||||
<h3 className="text-xl font-bold text-gray-900 mb-6">{pregunta.pregunta}</h3>
|
||||
|
||||
{/* Opciones */}
|
||||
{!mostrarResultado ? (
|
||||
<div className="space-y-3">
|
||||
{pregunta.opciones.map((opcion, index) => (
|
||||
<motion.button
|
||||
key={index}
|
||||
onClick={() => handleRespuesta(index)}
|
||||
whileHover={{ scale: 1.01 }}
|
||||
whileTap={{ scale: 0.99 }}
|
||||
className="w-full p-4 text-left border-2 border-gray-200 rounded-xl hover:border-blue-400 hover:bg-blue-50 transition-all"
|
||||
>
|
||||
<span className="font-medium text-gray-700">{String.fromCharCode(65 + index)}. {opcion}</span>
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className={`p-6 rounded-xl mb-6 ${esCorrecta ? 'bg-green-50 border border-green-200' : 'bg-red-50 border border-red-200'}`}
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
{esCorrecta ? (
|
||||
<CheckCircle className="w-6 h-6 text-green-600" />
|
||||
) : (
|
||||
<XCircle className="w-6 h-6 text-red-600" />
|
||||
)}
|
||||
<span className={`font-bold ${esCorrecta ? 'text-green-800' : 'text-red-800'}`}>
|
||||
{esCorrecta ? '¡Correcto!' : 'Incorrecto'}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-gray-700">{pregunta.explicacion}</p>
|
||||
|
||||
<Button onClick={handleSiguiente} className="mt-4">
|
||||
{esUltima ? 'Finalizar' : 'Siguiente'}
|
||||
</Button>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default DefinicionEconomiaQuiz;
|
||||
Reference in New Issue
Block a user