From fb8aecce97a673143147007fd5119408610f4155 Mon Sep 17 00:00:00 2001 From: MariaJoseMontepequeZet Date: Tue, 4 Aug 2026 13:42:19 -0600 Subject: [PATCH] Resolver ejercicio 72 intermedio --- .../maria-montepeque/maria-montepeque.html | 132 +++++++ .../maria-montepeque/maria-montepeque.js | 351 ++++++++++++++++++ 2 files changed, 483 insertions(+) create mode 100644 intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.html create mode 100644 intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.js diff --git a/intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.html b/intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.html new file mode 100644 index 0000000..5784068 --- /dev/null +++ b/intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.html @@ -0,0 +1,132 @@ + + + + + + 72. Menu interactivo comida + + + +

Menu del dia

+

Agrega productos al carrito y ajusta las cantidades.

+ +
+
+ +
+

Tu carrito

+
    +

    +

    +
    +
    + + + + diff --git a/intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.js b/intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.js new file mode 100644 index 0000000..90580d5 --- /dev/null +++ b/intermedio/ejercicios/72-menu-comida-app/resoluciones/maria-montepeque/maria-montepeque.js @@ -0,0 +1,351 @@ +// 72. Menu interactivo comida +// Resolucion: maria-montepeque +// +// Idea de la solucion: +// 1. Un menu fijo de productos (id, nombre, categoria, precio) y un carrito que es un array +// de items { id, nombre, categoria, precio, cantidad }, siempre tratado de forma inmutable. +// 2. Funciones pequenas para agregar, actualizar cantidad, eliminar y calcular totales con reduce. +// 3. El mismo archivo funciona con `node maria-montepeque.js` (corre casos de prueba por consola) +// y en el navegador (si se abre maria-montepeque.html) como un carrito interactivo real. + +// --------------------------------------------------------------------------- +// 1. Menu de productos +// --------------------------------------------------------------------------- + +const MENU_PRODUCTOS = [ + { id: 1, nombre: 'Hamburguesa clasica', categoria: 'platos fuertes', precio: 22000 }, + { id: 2, nombre: 'Pizza margarita', categoria: 'platos fuertes', precio: 35000 }, + { id: 3, nombre: 'Papas fritas', categoria: 'acompanamientos', precio: 12000 }, + { id: 4, nombre: 'Gaseosa', categoria: 'bebidas', precio: 6000 }, + { id: 5, nombre: 'Limonada natural', categoria: 'bebidas', precio: 7000 }, + { id: 6, nombre: 'Brownie', categoria: 'postres', precio: 10000 } +]; + +const UMBRAL_DESCUENTO = 80000; +const PORCENTAJE_DESCUENTO = 0.05; + +// --------------------------------------------------------------------------- +// 2. Consultas sobre el menu y el carrito +// --------------------------------------------------------------------------- + +function obtenerProductoPorId(idProducto) { + return MENU_PRODUCTOS.find((producto) => producto.id === idProducto); +} + +function encontrarItemCarrito(carrito, idProducto) { + return carrito.find((item) => item.id === idProducto); +} + +// --------------------------------------------------------------------------- +// 3. Validaciones +// --------------------------------------------------------------------------- + +function validarCantidad(cantidad) { + const numero = Number(cantidad); + if (!Number.isInteger(numero)) { + return { valido: false, motivo: 'La cantidad debe ser un numero entero.' }; + } + return { valido: true, numero }; +} + +// --------------------------------------------------------------------------- +// 4. Operaciones del carrito (inmutables: siempre devuelven un carrito nuevo) +// --------------------------------------------------------------------------- + +function agregarAlCarrito(carrito, idProducto, cantidad = 1) { + const producto = obtenerProductoPorId(idProducto); + if (!producto) { + return { exito: false, motivo: `No existe un producto con id ${idProducto}.`, carrito }; + } + + const validacion = validarCantidad(cantidad); + if (!validacion.valido || validacion.numero <= 0) { + return { exito: false, motivo: validacion.motivo ?? 'La cantidad debe ser mayor a 0.', carrito }; + } + + const itemExistente = encontrarItemCarrito(carrito, idProducto); + const carritoActualizado = itemExistente + ? carrito.map((item) => + item.id === idProducto ? { ...item, cantidad: item.cantidad + validacion.numero } : item + ) + : [ + ...carrito, + { + id: producto.id, + nombre: producto.nombre, + categoria: producto.categoria, + precio: producto.precio, + cantidad: validacion.numero + } + ]; + + return { exito: true, carrito: carritoActualizado }; +} + +function actualizarCantidadCarrito(carrito, idProducto, nuevaCantidad) { + if (!encontrarItemCarrito(carrito, idProducto)) { + return { exito: false, motivo: `El producto con id ${idProducto} no esta en el carrito.`, carrito }; + } + + const validacion = validarCantidad(nuevaCantidad); + if (!validacion.valido) { + return { exito: false, motivo: validacion.motivo, carrito }; + } + + if (validacion.numero <= 0) { + const carritoActualizado = carrito.filter((item) => item.id !== idProducto); + return { exito: true, carrito: carritoActualizado, eliminado: true }; + } + + const carritoActualizado = carrito.map((item) => + item.id === idProducto ? { ...item, cantidad: validacion.numero } : item + ); + return { exito: true, carrito: carritoActualizado }; +} + +function eliminarDelCarrito(carrito, idProducto) { + if (!encontrarItemCarrito(carrito, idProducto)) { + return { exito: false, motivo: `El producto con id ${idProducto} no esta en el carrito.`, carrito }; + } + return { exito: true, carrito: carrito.filter((item) => item.id !== idProducto) }; +} + +// --------------------------------------------------------------------------- +// 5. Calculos con reduce +// --------------------------------------------------------------------------- + +function calcularSubtotalItem(item) { + return item.precio * item.cantidad; +} + +function calcularTotalCarrito(carrito) { + return carrito.reduce((acumulado, item) => acumulado + calcularSubtotalItem(item), 0); +} + +function calcularCantidadTotalItems(carrito) { + return carrito.reduce((acumulado, item) => acumulado + item.cantidad, 0); +} + +// Reto extra: descuento automatico por monto alto + resumen de gasto por categoria. +function calcularDescuentoPorMonto(subtotal) { + return subtotal >= UMBRAL_DESCUENTO ? PORCENTAJE_DESCUENTO : 0; +} + +function generarResumenPorCategoria(carrito) { + return carrito.reduce((resumen, item) => { + resumen[item.categoria] = (resumen[item.categoria] ?? 0) + calcularSubtotalItem(item); + return resumen; + }, {}); +} + +function generarFacturaCarrito(carrito) { + const subtotal = calcularTotalCarrito(carrito); + const descuento = calcularDescuentoPorMonto(subtotal); + const total = Math.round(subtotal - subtotal * descuento); + + return { + cantidadItems: calcularCantidadTotalItems(carrito), + subtotal, + descuento, + total, + porCategoria: generarResumenPorCategoria(carrito) + }; +} + +// --------------------------------------------------------------------------- +// 6. Renderizado en consola +// --------------------------------------------------------------------------- + +function mostrarTablaEnConsola(etiqueta, filas) { + console.log(`\n${etiqueta}`); + if (filas.length === 0) { + console.log('(sin datos)'); + return; + } + if (typeof console.table === 'function') { + console.table(filas); + } else { + filas.forEach((fila) => console.log(fila)); + } +} + +function renderizarCarritoEnConsola(carrito) { + const filas = carrito.map((item) => ({ ...item, subtotal: calcularSubtotalItem(item) })); + mostrarTablaEnConsola('Carrito actual:', filas); +} + +// --------------------------------------------------------------------------- +// 7. Interfaz en el DOM +// --------------------------------------------------------------------------- + +function crearTarjetaProducto(producto, onAgregar) { + const tarjeta = document.createElement('article'); + tarjeta.className = 'producto'; + + const nombre = document.createElement('h3'); + nombre.textContent = producto.nombre; + + const detalle = document.createElement('p'); + detalle.textContent = `${producto.categoria} ยท $${producto.precio.toLocaleString('es-CO')}`; + + const botonAgregar = document.createElement('button'); + botonAgregar.type = 'button'; + botonAgregar.textContent = 'Agregar al carrito'; + botonAgregar.addEventListener('click', () => onAgregar(producto.id)); + + tarjeta.append(nombre, detalle, botonAgregar); + return tarjeta; +} + +function crearFilaCarrito(item, onCambiarCantidad, onEliminar) { + const fila = document.createElement('li'); + fila.className = 'item-carrito'; + + const nombre = document.createElement('span'); + nombre.textContent = item.nombre; + + const botonMenos = document.createElement('button'); + botonMenos.type = 'button'; + botonMenos.textContent = '-'; + botonMenos.addEventListener('click', () => onCambiarCantidad(item.id, item.cantidad - 1)); + + const cantidad = document.createElement('span'); + cantidad.textContent = item.cantidad; + + const botonMas = document.createElement('button'); + botonMas.type = 'button'; + botonMas.textContent = '+'; + botonMas.addEventListener('click', () => onCambiarCantidad(item.id, item.cantidad + 1)); + + const subtotal = document.createElement('span'); + subtotal.textContent = `$${calcularSubtotalItem(item).toLocaleString('es-CO')}`; + + const botonEliminar = document.createElement('button'); + botonEliminar.type = 'button'; + botonEliminar.textContent = 'Eliminar'; + botonEliminar.addEventListener('click', () => onEliminar(item.id)); + + fila.append(nombre, botonMenos, cantidad, botonMas, subtotal, botonEliminar); + return fila; +} + +function iniciarAplicacionDOM() { + const listaMenu = document.querySelector('#lista-menu'); + const listaCarrito = document.querySelector('#lista-carrito'); + const resumenElemento = document.querySelector('#resumen-carrito'); + const mensajeElemento = document.querySelector('#mensaje-estado'); + + if (!listaMenu || !listaCarrito || !resumenElemento || !mensajeElemento) return; + + let carritoActual = []; + + function actualizarResumen() { + const factura = generarFacturaCarrito(carritoActual); + resumenElemento.textContent = + `Items: ${factura.cantidadItems} | Subtotal: $${factura.subtotal.toLocaleString('es-CO')} | ` + + `Descuento: ${factura.descuento * 100}% | Total: $${factura.total.toLocaleString('es-CO')}`; + } + + function renderizarCarrito() { + listaCarrito.innerHTML = ''; + if (carritoActual.length === 0) { + const vacio = document.createElement('li'); + vacio.textContent = 'El carrito esta vacio.'; + listaCarrito.appendChild(vacio); + } else { + carritoActual.forEach((item) => { + listaCarrito.appendChild(crearFilaCarrito(item, manejarCambioCantidad, manejarEliminar)); + }); + } + actualizarResumen(); + } + + function manejarAgregar(idProducto) { + const resultado = agregarAlCarrito(carritoActual, idProducto, 1); + if (!resultado.exito) { + mensajeElemento.textContent = resultado.motivo; + mensajeElemento.className = 'mensaje error'; + return; + } + carritoActual = resultado.carrito; + mensajeElemento.textContent = ''; + mensajeElemento.className = 'mensaje'; + renderizarCarrito(); + } + + function manejarCambioCantidad(idProducto, nuevaCantidad) { + const resultado = actualizarCantidadCarrito(carritoActual, idProducto, nuevaCantidad); + if (!resultado.exito) { + mensajeElemento.textContent = resultado.motivo; + mensajeElemento.className = 'mensaje error'; + return; + } + carritoActual = resultado.carrito; + renderizarCarrito(); + } + + function manejarEliminar(idProducto) { + const resultado = eliminarDelCarrito(carritoActual, idProducto); + if (!resultado.exito) { + mensajeElemento.textContent = resultado.motivo; + mensajeElemento.className = 'mensaje error'; + return; + } + carritoActual = resultado.carrito; + renderizarCarrito(); + } + + MENU_PRODUCTOS.forEach((producto) => { + listaMenu.appendChild(crearTarjetaProducto(producto, manejarAgregar)); + }); + + renderizarCarrito(); +} + +// --------------------------------------------------------------------------- +// 8. Ejecucion por consola (node maria-montepeque.js) con al menos dos casos de prueba +// --------------------------------------------------------------------------- + +function resolverEjercicio() { + console.log('=== 72. Menu interactivo comida ==='); + mostrarTablaEnConsola('Menu disponible:', MENU_PRODUCTOS); + + // Caso 1: flujo normal - agregar productos validos, subir cantidad, ver total y descuento. + console.log('\nCaso 1 - flujo normal de compra:'); + let carrito = []; + carrito = agregarAlCarrito(carrito, 1, 2).carrito; // 2 hamburguesas + carrito = agregarAlCarrito(carrito, 2, 1).carrito; // 1 pizza + carrito = agregarAlCarrito(carrito, 4, 2).carrito; // 2 gaseosas + const resultadoActualizar = actualizarCantidadCarrito(carrito, 4, 3); // sube gaseosas a 3 + carrito = resultadoActualizar.carrito; + + renderizarCarritoEnConsola(carrito); + console.log('Factura:', generarFacturaCarrito(carrito)); + + // Caso 2: casos limite y errores - producto inexistente, cantidad invalida, eliminar item + // que no esta en el carrito, y bajar la cantidad a 0 (debe eliminar el item). + console.log('\nCaso 2 - validaciones y casos limite:'); + const productoInexistente = agregarAlCarrito(carrito, 999, 1); + console.log('Agregar producto inexistente:', productoInexistente.exito ? 'agregado' : productoInexistente.motivo); + + const cantidadInvalida = agregarAlCarrito(carrito, 3, -2); + console.log('Agregar cantidad negativa:', cantidadInvalida.exito ? 'agregado' : cantidadInvalida.motivo); + + const eliminarInexistente = eliminarDelCarrito(carrito, 5); + console.log('Eliminar producto que no esta en el carrito:', eliminarInexistente.exito ? 'ok' : eliminarInexistente.motivo); + + const bajarACero = actualizarCantidadCarrito(carrito, 1, 0); + console.log('Bajar cantidad de hamburguesas a 0:', bajarACero.eliminado ? 'item eliminado del carrito' : 'sin cambios'); + carrito = bajarACero.carrito; + + renderizarCarritoEnConsola(carrito); + console.log('Factura final:', generarFacturaCarrito(carrito)); + + return { carritoFinal: carrito }; +} + +if (typeof document !== 'undefined') { + document.addEventListener('DOMContentLoaded', iniciarAplicacionDOM); +} else { + resolverEjercicio(); +}