247 lines
9.4 KiB
TypeScript
247 lines
9.4 KiB
TypeScript
import { useState } from 'react';
|
|
|
|
interface CostoOportunidadCotidianoProps {
|
|
ejercicioId: string;
|
|
onComplete?: (puntuacion: number) => void;
|
|
}
|
|
|
|
interface Situacion {
|
|
id: number;
|
|
titulo: string;
|
|
descripcion: string;
|
|
decision: string;
|
|
opciones: string[];
|
|
costoOportunidadCorrecto: string;
|
|
explicacion: string;
|
|
}
|
|
|
|
const situaciones: Situacion[] = [
|
|
{
|
|
id: 1,
|
|
titulo: "Tiempo libre",
|
|
descripcion: "Tienes 3 horas libres un sábado por la tarde.",
|
|
decision: "Decides estudiar para un examen importante.",
|
|
opciones: [
|
|
"El tiempo que podrías haber pasado con amigos",
|
|
"Las calificaciones del examen",
|
|
"El dinero ahorrado",
|
|
"La comida que no comiste"
|
|
],
|
|
costoOportunidadCorrecto: "El tiempo que podrías haber pasado con amigos",
|
|
explicacion: "El costo de oportunidad es lo que sacrificas: el tiempo con amigos que elegiste no hacer."
|
|
},
|
|
{
|
|
id: 2,
|
|
titulo: "Compra de tecnología",
|
|
descripcion: "Tienes $1,000 ahorrados.",
|
|
decision: "Compras una laptop nueva para trabajar.",
|
|
opciones: [
|
|
"El dinero que gastaste",
|
|
"El dinero que podrías haber invertido",
|
|
"La laptop misma",
|
|
"Las especificaciones técnicas"
|
|
],
|
|
costoOportunidadCorrecto: "El dinero que podrías haber invertido",
|
|
explicacion: "Al gastar en la laptop, sacrificas la oportunidad de invertir ese dinero y obtener rendimientos."
|
|
},
|
|
{
|
|
id: 3,
|
|
titulo: "Carrera profesional",
|
|
descripcion: "Terminas la universidad con dos ofertas de trabajo.",
|
|
decision: "Aceptas el trabajo en una startup con menor salario inicial.",
|
|
opciones: [
|
|
"El salario más alto de la otra oferta",
|
|
"La experiencia en la startup",
|
|
"Tu título universitario",
|
|
"El tiempo de búsqueda"
|
|
],
|
|
costoOportunidadCorrecto: "El salario más alto de la otra oferta",
|
|
explicacion: "Al elegir la startup, renuncias al salario más alto que ofrecía la otra empresa."
|
|
},
|
|
{
|
|
id: 4,
|
|
titulo: "Vacaciones",
|
|
descripcion: "Tienes dos semanas de vacaciones este verano.",
|
|
decision: "Viajas a Europa en lugar de quedarte trabajando.",
|
|
opciones: [
|
|
"Las fotos que tomarás",
|
|
"El dinero que gastarás en el viaje",
|
|
"El dinero que podrías haber ganado trabajando",
|
|
"La experiencia cultural"
|
|
],
|
|
costoOportunidadCorrecto: "El dinero que podrías haber ganado trabajando",
|
|
explicacion: "El costo de oportunidad incluye los ingresos que sacrificas al no trabajar esas semanas."
|
|
}
|
|
];
|
|
|
|
export function CostoOportunidadCotidiano({ ejercicioId: _ejercicioId, onComplete }: CostoOportunidadCotidianoProps) {
|
|
const [respuestas, setRespuestas] = useState<{[key: number]: string}>({});
|
|
const [mostrarExplicacion, setMostrarExplicacion] = useState<{[key: number]: boolean}>({});
|
|
const [completado, setCompletado] = useState(false);
|
|
|
|
const handleSeleccion = (situacionId: number, opcion: string) => {
|
|
setRespuestas(prev => ({ ...prev, [situacionId]: opcion }));
|
|
};
|
|
|
|
const handleValidar = () => {
|
|
const nuevasExplicaciones: {[key: number]: boolean} = {};
|
|
let correctas = 0;
|
|
|
|
situaciones.forEach(situacion => {
|
|
nuevasExplicaciones[situacion.id] = true;
|
|
if (respuestas[situacion.id] === situacion.costoOportunidadCorrecto) {
|
|
correctas++;
|
|
}
|
|
});
|
|
|
|
setMostrarExplicacion(nuevasExplicaciones);
|
|
|
|
if (correctas === situaciones.length && !completado) {
|
|
setCompletado(true);
|
|
if (onComplete) {
|
|
onComplete(100);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleReset = () => {
|
|
setRespuestas({});
|
|
setMostrarExplicacion({});
|
|
setCompletado(false);
|
|
};
|
|
|
|
const correctas = situaciones.filter(s => respuestas[s.id] === s.costoOportunidadCorrecto).length;
|
|
|
|
return (
|
|
<div className="w-full max-w-4xl mx-auto bg-white rounded-lg shadow-lg p-6">
|
|
<div className="mb-6">
|
|
<h3 className="text-xl font-semibold text-gray-900">Costo de Oportunidad en Decisiones Cotidianas</h3>
|
|
<p className="text-sm text-gray-500 mt-1">
|
|
Identifica el costo de oportunidad en cada situación de la vida real.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="bg-amber-50 border border-amber-200 rounded-lg p-4 mb-6">
|
|
<p className="text-amber-800 text-sm">
|
|
<strong>Recuerda:</strong> El costo de oportunidad es el valor de la mejor alternativa a la que renuncias
|
|
al tomar una decisión. No es lo que gastas, sino lo que sacrificas.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-6">
|
|
{situaciones.map((situacion, index) => (
|
|
<div
|
|
key={situacion.id}
|
|
className="border border-gray-200 rounded-lg p-5 hover:shadow-md transition-shadow"
|
|
>
|
|
<div className="flex items-start gap-4">
|
|
<div className="flex-shrink-0 w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center text-blue-600 font-bold">
|
|
{index + 1}
|
|
</div>
|
|
<div className="flex-grow">
|
|
<h4 className="font-semibold text-gray-900 text-lg">{situacion.titulo}</h4>
|
|
<p className="text-gray-600 mt-1">{situacion.descripcion}</p>
|
|
<p className="text-blue-700 font-medium mt-2">Decisión: {situacion.decision}</p>
|
|
|
|
<div className="mt-4">
|
|
<p className="text-sm font-medium text-gray-700 mb-3">
|
|
¿Cuál es el costo de oportunidad?
|
|
</p>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
{situacion.opciones.map((opcion) => {
|
|
const isSelected = respuestas[situacion.id] === opcion;
|
|
const isCorrect = opcion === situacion.costoOportunidadCorrecto;
|
|
const showResult = mostrarExplicacion[situacion.id];
|
|
|
|
let buttonClass = 'border border-gray-300 bg-white text-gray-700 hover:bg-gray-50';
|
|
|
|
if (showResult) {
|
|
if (isCorrect) {
|
|
buttonClass = 'border-green-500 bg-green-50 text-green-800';
|
|
} else if (isSelected && !isCorrect) {
|
|
buttonClass = 'border-red-500 bg-red-50 text-red-800';
|
|
} else {
|
|
buttonClass = 'border-gray-200 bg-gray-50 text-gray-400';
|
|
}
|
|
} else if (isSelected) {
|
|
buttonClass = 'border-blue-500 bg-blue-50 text-blue-800';
|
|
}
|
|
|
|
return (
|
|
<button
|
|
key={opcion}
|
|
onClick={() => !showResult && handleSeleccion(situacion.id, opcion)}
|
|
disabled={showResult}
|
|
className={`p-3 rounded-lg text-left text-sm transition-all ${buttonClass}`}
|
|
>
|
|
{opcion}
|
|
{showResult && isCorrect && (
|
|
<span className="ml-2 text-green-600 font-bold">✓</span>
|
|
)}
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{mostrarExplicacion[situacion.id] && (
|
|
<div className={`mt-4 p-4 rounded-lg ${
|
|
respuestas[situacion.id] === situacion.costoOportunidadCorrecto
|
|
? 'bg-green-50 border border-green-200'
|
|
: 'bg-amber-50 border border-amber-200'
|
|
}`}>
|
|
<p className={`text-sm font-medium ${
|
|
respuestas[situacion.id] === situacion.costoOportunidadCorrecto
|
|
? 'text-green-800'
|
|
: 'text-amber-800'
|
|
}`}>
|
|
{respuestas[situacion.id] === situacion.costoOportunidadCorrecto
|
|
? '¡Correcto!'
|
|
: 'Respuesta correcta:'}
|
|
</p>
|
|
<p className={`text-sm mt-1 ${
|
|
respuestas[situacion.id] === situacion.costoOportunidadCorrecto
|
|
? 'text-green-700'
|
|
: 'text-amber-700'
|
|
}`}>
|
|
{situacion.explicacion}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div className="mt-6 flex gap-3">
|
|
<button
|
|
onClick={handleValidar}
|
|
disabled={completado || Object.keys(respuestas).length < situaciones.length}
|
|
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400 transition-colors"
|
|
>
|
|
Validar Respuestas
|
|
</button>
|
|
<button
|
|
onClick={handleReset}
|
|
className="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
|
>
|
|
Reiniciar
|
|
</button>
|
|
</div>
|
|
|
|
{completado && (
|
|
<div className="mt-6 bg-green-100 border border-green-300 rounded-lg p-4 text-center">
|
|
<p className="text-green-800 font-semibold">¡Excelente comprensión!</p>
|
|
<p className="text-green-700 text-2xl font-bold mt-1">100 puntos</p>
|
|
<p className="text-green-700 text-sm mt-2">
|
|
Has identificado correctamente todos los costos de oportunidad.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default CostoOportunidadCotidiano;
|