Initial commit - cleaned for CV
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { Card, CardHeader } from '../../ui/Card';
|
||||
import { Button } from '../../ui/Button';
|
||||
import { CheckCircle, RotateCcw, HelpCircle, AlertCircle } from 'lucide-react';
|
||||
|
||||
interface ClasificacionElasticidadProps {
|
||||
ejercicioId: string;
|
||||
onComplete?: (puntuacion: number) => void;
|
||||
}
|
||||
|
||||
type TipoElasticidad = 'elastica' | 'unitaria' | 'inelastica';
|
||||
|
||||
interface EjercicioData {
|
||||
ep: number;
|
||||
descripcion: string;
|
||||
explicacion: string;
|
||||
}
|
||||
|
||||
const ejercicios: EjercicioData[] = [
|
||||
{
|
||||
ep: -2.5,
|
||||
descripcion: 'Un producto tiene una elasticidad precio de -2.5. ¿Cómo se clasifica?',
|
||||
explicacion: '|Ep| = 2.5 > 1 → Demanda ELÁSTICA. El % de cambio en cantidad es mayor que el % de cambio en precio.',
|
||||
},
|
||||
{
|
||||
ep: -0.3,
|
||||
descripcion: 'La elasticidad precio de un bien es -0.3. ¿Qué tipo de demanda tiene?',
|
||||
explicacion: '|Ep| = 0.3 < 1 → Demanda INELÁSTICA. El % de cambio en cantidad es menor que el % de cambio en precio.',
|
||||
},
|
||||
{
|
||||
ep: -1.0,
|
||||
descripcion: 'Un artículo tiene elasticidad precio igual a -1. ¿Cómo se clasifica?',
|
||||
explicacion: '|Ep| = 1 → Demanda UNITARIA. El % de cambio en cantidad es igual al % de cambio en precio.',
|
||||
},
|
||||
{
|
||||
ep: -0.8,
|
||||
descripcion: 'La elasticidad de un medicamento es de -0.8. ¿Qué tipo de elasticidad tiene?',
|
||||
explicacion: '|Ep| = 0.8 < 1 → Demanda INELÁSTICA. Los medicamentos suelen ser inelásticos porque son necesidades básicas.',
|
||||
},
|
||||
{
|
||||
ep: -4.2,
|
||||
descripcion: 'Un restaurante de lujo tiene elasticidad de -4.2. ¿Cómo se clasifica?',
|
||||
explicacion: '|Ep| = 4.2 > 1 → Demanda ELÁSTICA. Los lujos suelen tener demanda muy elástica porque son opcionales.',
|
||||
},
|
||||
];
|
||||
|
||||
export function ClasificacionElasticidad({ ejercicioId: _ejercicioId, onComplete }: ClasificacionElasticidadProps) {
|
||||
const [ejercicioIndex, setEjercicioIndex] = useState(0);
|
||||
const [respuesta, setRespuesta] = useState<TipoElasticidad | null>(null);
|
||||
const [validado, setValidado] = useState(false);
|
||||
const [aciertos, setAciertos] = useState(0);
|
||||
const [completado, setCompletado] = useState(false);
|
||||
|
||||
const ejercicio = ejercicios[ejercicioIndex];
|
||||
|
||||
const obtenerRespuestaCorrecta = useCallback((ep: number): TipoElasticidad => {
|
||||
const valorAbs = Math.abs(ep);
|
||||
if (valorAbs > 1) return 'elastica';
|
||||
if (valorAbs < 1) return 'inelastica';
|
||||
return 'unitaria';
|
||||
}, []);
|
||||
|
||||
const validarRespuesta = () => {
|
||||
if (!respuesta) return;
|
||||
|
||||
const correcta = obtenerRespuestaCorrecta(ejercicio.ep);
|
||||
const esCorrecto = respuesta === correcta;
|
||||
|
||||
setValidado(true);
|
||||
|
||||
if (esCorrecto) {
|
||||
setAciertos((prev) => prev + 1);
|
||||
}
|
||||
|
||||
if (ejercicioIndex === ejercicios.length - 1) {
|
||||
setCompletado(true);
|
||||
if (onComplete) {
|
||||
const puntuacion = Math.round((aciertos + (esCorrecto ? 1 : 0)) / ejercicios.length * 100);
|
||||
onComplete(puntuacion);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const siguienteEjercicio = () => {
|
||||
if (ejercicioIndex < ejercicios.length - 1) {
|
||||
setEjercicioIndex((prev) => prev + 1);
|
||||
setRespuesta(null);
|
||||
setValidado(false);
|
||||
}
|
||||
};
|
||||
|
||||
const reiniciar = () => {
|
||||
setEjercicioIndex(0);
|
||||
setRespuesta(null);
|
||||
setValidado(false);
|
||||
setAciertos(0);
|
||||
setCompletado(false);
|
||||
};
|
||||
|
||||
const respuestaCorrecta = obtenerRespuestaCorrecta(ejercicio.ep);
|
||||
|
||||
const opciones: { value: TipoElasticidad; label: string; color: string }[] = [
|
||||
{ value: 'elastica', label: 'Elástica (|Ep| > 1)', color: 'bg-green-100 border-green-300 text-green-800' },
|
||||
{ value: 'unitaria', label: 'Unitaria (|Ep| = 1)', color: 'bg-yellow-100 border-yellow-300 text-yellow-800' },
|
||||
{ value: 'inelastica', label: 'Inelástica (|Ep| < 1)', color: 'bg-blue-100 border-blue-300 text-blue-800' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader
|
||||
title="Clasificación de Elasticidad"
|
||||
subtitle="Identifica si la demanda es elástica, unitaria o inelástica"
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 mb-6">
|
||||
<div className="bg-green-50 border-2 border-green-200 rounded-lg p-4 text-center">
|
||||
<h4 className="font-bold text-green-800 mb-1">ELÁSTICA</h4>
|
||||
<p className="text-2xl font-bold text-green-600">|Ep| > 1</p>
|
||||
<p className="text-xs text-green-700 mt-1">%ΔQ > %ΔP</p>
|
||||
</div>
|
||||
<div className="bg-yellow-50 border-2 border-yellow-200 rounded-lg p-4 text-center">
|
||||
<h4 className="font-bold text-yellow-800 mb-1">UNITARIA</h4>
|
||||
<p className="text-2xl font-bold text-yellow-600">|Ep| = 1</p>
|
||||
<p className="text-xs text-yellow-700 mt-1">%ΔQ = %ΔP</p>
|
||||
</div>
|
||||
<div className="bg-blue-50 border-2 border-blue-200 rounded-lg p-4 text-center">
|
||||
<h4 className="font-bold text-blue-800 mb-1">INELÁSTICA</h4>
|
||||
<p className="text-2xl font-bold text-blue-600">|Ep| < 1</p>
|
||||
<p className="text-xs text-blue-700 mt-1">%ΔQ < %ΔP</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<span className="bg-primary text-white text-xs font-bold px-2 py-1 rounded">
|
||||
{ejercicioIndex + 1}/{ejercicios.length}
|
||||
</span>
|
||||
<h4 className="font-medium text-gray-700">Pregunta:</h4>
|
||||
</div>
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<p className="text-gray-800 mb-3">{ejercicio.descripcion}</p>
|
||||
<p className="text-lg font-bold text-primary">
|
||||
E<sub>p</sub> = {ejercicio.ep}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 mb-6">
|
||||
{opciones.map((opcion) => (
|
||||
<button
|
||||
key={opcion.value}
|
||||
onClick={() => {
|
||||
setRespuesta(opcion.value);
|
||||
setValidado(false);
|
||||
}}
|
||||
disabled={validado}
|
||||
className={`w-full p-4 rounded-lg border-2 text-left transition-all ${
|
||||
respuesta === opcion.value
|
||||
? opcion.color
|
||||
: 'bg-white border-gray-200 hover:border-gray-300'
|
||||
} ${validado && respuestaCorrecta === opcion.value ? 'ring-2 ring-success' : ''}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium">{opcion.label}</span>
|
||||
{validado && respuestaCorrecta === opcion.value && (
|
||||
<CheckCircle className="w-5 h-5 text-success" />
|
||||
)}
|
||||
{validado && respuesta === opcion.value && respuesta !== respuestaCorrecta && (
|
||||
<AlertCircle className="w-5 h-5 text-error" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{validado && (
|
||||
<div className="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6">
|
||||
<h4 className="font-medium text-blue-900 mb-1 flex items-center gap-2">
|
||||
<HelpCircle className="w-4 h-4" />
|
||||
Explicación:
|
||||
</h4>
|
||||
<p className="text-blue-800">{ejercicio.explicacion}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-3">
|
||||
{!validado ? (
|
||||
<Button onClick={validarRespuesta} variant="primary" disabled={!respuesta}>
|
||||
<CheckCircle className="w-4 h-4 mr-2" />
|
||||
Validar Respuesta
|
||||
</Button>
|
||||
) : ejercicioIndex < ejercicios.length - 1 ? (
|
||||
<Button onClick={siguienteEjercicio} variant="primary">
|
||||
Siguiente Ejercicio
|
||||
</Button>
|
||||
) : (
|
||||
<Button onClick={reiniciar} variant="primary">
|
||||
<RotateCcw className="w-4 h-4 mr-2" />
|
||||
Reiniciar
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{completado && (
|
||||
<div className="mt-4 p-4 bg-success/10 border border-success rounded-lg">
|
||||
<p className="text-success font-medium text-center">
|
||||
¡Completado! Has acertado {aciertos + (respuesta === respuestaCorrecta ? 1 : 0)} de{' '}
|
||||
{ejercicios.length} ejercicios
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<Card className="bg-purple-50 border-purple-200">
|
||||
<h4 className="font-semibold text-purple-900 mb-2">Interpretación Económica:</h4>
|
||||
<ul className="space-y-2 text-sm text-purple-800">
|
||||
<li>
|
||||
<strong>Elástica (|Ep| > 1):</strong> Los consumidores son muy sensibles al precio.
|
||||
Un cambio de precio genera un cambio proporcionalmente mayor en cantidad demandada.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Unitaria (|Ep| = 1):</strong> Sensibilidad proporcional.
|
||||
El gasto total de los consumidores se mantiene constante ante cambios de precio.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Inelástica (|Ep| < 1):</strong> Los consumidores son poco sensibles al precio.
|
||||
La cantidad demandada cambia menos que proporcionalmente al precio.
|
||||
</li>
|
||||
</ul>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ClasificacionElasticidad;
|
||||
Reference in New Issue
Block a user