Spaces:
Runtime error
Runtime error
| // SoberanIA Argentina 2025 - App.js | |
| // Ecosistema Fintech Cooperativo | |
| // Datos de la aplicaci贸n | |
| const appData = { | |
| usuarios: { | |
| total: 783173, | |
| jubilados: 274211, | |
| vulnerables: 195793, | |
| generales: 313169 | |
| }, | |
| redistribucion: { | |
| total_acumulado: 45320780000, | |
| mes_actual: 8500000 | |
| }, | |
| transacciones: { | |
| volumen_mensual: 32654892300, | |
| p2p: 45, | |
| marketplace: 35, | |
| inversiones: 15, | |
| creditos: 5 | |
| }, | |
| sorteos: { | |
| fondo_actual: 12500000, | |
| ganadores_mes: { | |
| jubilados: 23, | |
| vulnerables: 8, | |
| generales: 5 | |
| }, | |
| proximo_sorteo: "2025-06-15T20:00:00" | |
| }, | |
| impacto: { | |
| soberania_economica: 45, | |
| inclusion_financiera: 67, | |
| mejora_jubilados: 73, | |
| ahorro_comisiones: 4500000000 | |
| }, | |
| cooperativas: { | |
| comercios_adheridos: 8742, | |
| provincias_activas: 24, | |
| municipios_participantes: 1247 | |
| } | |
| }; | |
| // DOM Elements | |
| const domElements = { | |
| // Navegaci贸n | |
| navLinks: document.querySelectorAll('.nav__link'), | |
| navToggle: document.getElementById('navToggle'), | |
| navMenu: document.getElementById('navMenu'), | |
| // Secciones | |
| sections: document.querySelectorAll('.section'), | |
| // Tema | |
| themeToggle: document.getElementById('themeToggle'), | |
| // Login | |
| loginBtn: document.getElementById('loginBtn'), | |
| registerBtn: document.getElementById('registerBtn'), | |
| loginModal: document.getElementById('loginModal'), | |
| closeModal: document.getElementById('closeModal'), | |
| biometricLogin: document.getElementById('biometricLogin'), | |
| // Contadores | |
| counters: document.querySelectorAll('.metric-card__number'), | |
| // Simulador de inversiones | |
| investmentAmount: document.getElementById('investmentAmount'), | |
| investmentTerm: document.getElementById('investmentTerm'), | |
| simulateBtn: document.getElementById('simulateBtn'), | |
| simulationResult: document.getElementById('simulationResult'), | |
| estimatedReturn: document.getElementById('estimatedReturn'), | |
| annualRate: document.getElementById('annualRate'), | |
| totalReturn: document.getElementById('totalReturn'), | |
| // Sorteo Countdown | |
| days: document.getElementById('days'), | |
| hours: document.getElementById('hours'), | |
| minutes: document.getElementById('minutes'), | |
| seconds: document.getElementById('seconds'), | |
| sorteoCountdown: document.getElementById('sorteoCountdown'), | |
| // Calculadora de probabilidades | |
| userCategory: document.getElementById('userCategory'), | |
| // Contenedor de notificaciones | |
| notificationContainer: document.getElementById('notificationContainer'), | |
| // Aprendizaje | |
| learnMoreBtn: document.getElementById('learnMoreBtn') | |
| }; | |
| // Inicializaci贸n de la aplicaci贸n | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Inicializar navegaci贸n | |
| initNavigation(); | |
| // Inicializar tema | |
| initTheme(); | |
| // Inicializar contadores | |
| initCounters(); | |
| // Inicializar simulador | |
| initSimulator(); | |
| // Inicializar cuenta regresiva | |
| initCountdown(); | |
| // Inicializar modales | |
| initModals(); | |
| // Inicializar calculadora de probabilidades | |
| initProbabilityCalculator(); | |
| // Inicializar funcionalidades del marketplace | |
| initMarketplace(); | |
| // Inicializar funcionalidades del DAO | |
| initDAO(); | |
| // Mostrar notificaci贸n de bienvenida despu茅s de 3 segundos | |
| setTimeout(() => { | |
| showNotification({ | |
| type: 'success', | |
| title: '隆Bienvenido a SoberanIA Argentina 2025!', | |
| message: 'Juntos construimos la primera econom铆a digitalmente soberana' | |
| }); | |
| }, 3000); | |
| }); | |
| // Funci贸n para inicializar la navegaci贸n | |
| function initNavigation() { | |
| // Manejar clic en enlaces de navegaci贸n | |
| domElements.navLinks.forEach(link => { | |
| link.addEventListener('click', (e) => { | |
| e.preventDefault(); | |
| // Remover clase activa de todos los enlaces | |
| domElements.navLinks.forEach(item => item.classList.remove('active')); | |
| // Agregar clase activa al enlace clickeado | |
| link.classList.add('active'); | |
| // Obtener el ID de la secci贸n a mostrar | |
| const targetId = link.getAttribute('href').substring(1); | |
| // Ocultar todas las secciones | |
| domElements.sections.forEach(section => { | |
| section.classList.remove('section--active'); | |
| }); | |
| // Mostrar la secci贸n seleccionada | |
| document.getElementById(targetId).classList.add('section--active'); | |
| // Si el men煤 m贸vil est谩 abierto, cerrarlo | |
| if (domElements.navMenu && domElements.navMenu.classList.contains('active')) { | |
| domElements.navMenu.classList.remove('active'); | |
| toggleHamburgerIcon(); | |
| } | |
| // Scroll al inicio de la secci贸n | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| }); | |
| }); | |
| // Manejar toggle del men煤 en m贸vil | |
| if (domElements.navToggle) { | |
| domElements.navToggle.addEventListener('click', () => { | |
| if (domElements.navMenu) { | |
| domElements.navMenu.classList.toggle('active'); | |
| toggleHamburgerIcon(); | |
| } | |
| }); | |
| } | |
| // Funci贸n para animar el 铆cono hamburguesa | |
| function toggleHamburgerIcon() { | |
| if (!domElements.navToggle) return; | |
| const spans = domElements.navToggle.querySelectorAll('span'); | |
| spans.forEach(span => span.classList.toggle('active')); | |
| if (spans[0].classList.contains('active')) { | |
| spans[0].style.transform = 'rotate(45deg) translate(5px, 5px)'; | |
| spans[1].style.opacity = '0'; | |
| spans[2].style.transform = 'rotate(-45deg) translate(7px, -7px)'; | |
| } else { | |
| spans[0].style.transform = 'none'; | |
| spans[1].style.opacity = '1'; | |
| spans[2].style.transform = 'none'; | |
| } | |
| } | |
| } | |
| // Funci贸n para inicializar el tema | |
| function initTheme() { | |
| if (!domElements.themeToggle) return; | |
| // Verificar si hay un tema guardado en localStorage | |
| const savedTheme = 'light'; // Por defecto usamos claro debido a las restricciones de localStorage | |
| // Aplicar tema guardado o detectar preferencia del sistema | |
| if (savedTheme) { | |
| document.documentElement.setAttribute('data-color-scheme', savedTheme); | |
| updateThemeIcon(savedTheme); | |
| } else { | |
| // Detectar preferencia del sistema | |
| const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; | |
| const theme = prefersDarkMode ? 'dark' : 'light'; | |
| document.documentElement.setAttribute('data-color-scheme', theme); | |
| updateThemeIcon(theme); | |
| } | |
| // Manejar cambio de tema | |
| domElements.themeToggle.addEventListener('click', () => { | |
| const currentTheme = document.documentElement.getAttribute('data-color-scheme'); | |
| const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; | |
| document.documentElement.setAttribute('data-color-scheme', newTheme); | |
| updateThemeIcon(newTheme); | |
| // Simulaci贸n de guardado en localStorage (no usado realmente por las restricciones) | |
| console.log(`Tema cambiado a: ${newTheme}`); | |
| // Mostrar notificaci贸n | |
| showNotification({ | |
| type: 'info', | |
| title: 'Tema cambiado', | |
| message: `Has cambiado al tema ${newTheme === 'dark' ? 'oscuro' : 'claro'}` | |
| }); | |
| }); | |
| // Actualizar 铆cono seg煤n el tema | |
| function updateThemeIcon(theme) { | |
| if (theme === 'dark') { | |
| domElements.themeToggle.innerHTML = '<i class="fas fa-sun"></i>'; | |
| } else { | |
| domElements.themeToggle.innerHTML = '<i class="fas fa-moon"></i>'; | |
| } | |
| } | |
| } | |
| // Funci贸n para inicializar los contadores animados | |
| function initCounters() { | |
| domElements.counters.forEach(counter => { | |
| if (!counter) return; | |
| const target = parseInt(counter.getAttribute('data-target').replace(/,/g, '')); | |
| const prefix = counter.getAttribute('data-prefix') || ''; | |
| const suffix = counter.getAttribute('data-suffix') || ''; | |
| const formatter = new Intl.NumberFormat('es-AR'); | |
| // Duraci贸n de la animaci贸n en ms | |
| const duration = 2000; | |
| const frameRate = 1000 / 60; // 60 fps | |
| const frames = duration / frameRate; | |
| // Incremento por frame | |
| const increment = target / frames; | |
| let currentCount = 0; | |
| // Funci贸n de animaci贸n | |
| function animate() { | |
| currentCount += increment; | |
| if (currentCount < target) { | |
| counter.textContent = prefix + formatter.format(Math.floor(currentCount)) + suffix; | |
| requestAnimationFrame(animate); | |
| } else { | |
| counter.textContent = prefix + formatter.format(target) + suffix; | |
| } | |
| } | |
| // Iniciar animaci贸n cuando el elemento est茅 en el viewport | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach(entry => { | |
| if (entry.isIntersecting) { | |
| animate(); | |
| observer.disconnect(); | |
| } | |
| }); | |
| }, { threshold: 0.1 }); | |
| observer.observe(counter); | |
| }); | |
| } | |
| // Funci贸n para inicializar el simulador de inversiones | |
| function initSimulator() { | |
| if (!domElements.simulateBtn) return; | |
| domElements.simulateBtn.addEventListener('click', () => { | |
| const amount = parseFloat(domElements.investmentAmount.value); | |
| const term = parseInt(domElements.investmentTerm.value); | |
| // Validaci贸n | |
| if (isNaN(amount) || amount <= 0) { | |
| showNotification({ | |
| type: 'error', | |
| title: 'Error en la simulaci贸n', | |
| message: 'Ingrese un monto v谩lido para la inversi贸n' | |
| }); | |
| return; | |
| } | |
| // Tasas de inter茅s seg煤n plazo (simuladas) | |
| const rates = { | |
| 30: 65, // 65% anual para 30 d铆as | |
| 90: 70, // 70% anual para 90 d铆as | |
| 180: 75, // 75% anual para 180 d铆as | |
| 365: 80 // 80% anual para 365 d铆as | |
| }; | |
| const annualRate = rates[term]; | |
| const periodRate = annualRate * (term / 365); | |
| const interest = amount * (periodRate / 100); | |
| const total = amount + interest; | |
| // Formatear valores | |
| const formatter = new Intl.NumberFormat('es-AR', { | |
| style: 'currency', | |
| currency: 'ARS' | |
| }); | |
| // Actualizar resultados | |
| if (domElements.estimatedReturn) { | |
| domElements.estimatedReturn.textContent = formatter.format(interest); | |
| } | |
| if (domElements.annualRate) { | |
| domElements.annualRate.textContent = annualRate + '%'; | |
| } | |
| if (domElements.totalReturn) { | |
| domElements.totalReturn.textContent = formatter.format(total); | |
| } | |
| // Mostrar resultados | |
| if (domElements.simulationResult) { | |
| domElements.simulationResult.style.display = 'block'; | |
| } | |
| // Mostrar notificaci贸n | |
| showNotification({ | |
| type: 'success', | |
| title: 'Simulaci贸n completa', | |
| message: `Rendimiento estimado: ${formatter.format(interest)}` | |
| }); | |
| }); | |
| } | |
| // Funci贸n para inicializar la cuenta regresiva del sorteo | |
| function initCountdown() { | |
| // Fecha del pr贸ximo sorteo desde los datos | |
| const targetDate = new Date(appData.sorteos.proximo_sorteo); | |
| // Actualizar la cuenta regresiva cada segundo | |
| function updateCountdown() { | |
| const currentDate = new Date(); | |
| const difference = targetDate - currentDate; | |
| // Calcular d铆as, horas, minutos y segundos | |
| const days = Math.floor(difference / (1000 * 60 * 60 * 24)); | |
| const hours = Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); | |
| const minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); | |
| const seconds = Math.floor((difference % (1000 * 60)) / 1000); | |
| // Actualizar elementos DOM | |
| if (domElements.days) domElements.days.textContent = days; | |
| if (domElements.hours) domElements.hours.textContent = hours; | |
| if (domElements.minutes) domElements.minutes.textContent = minutes; | |
| if (domElements.seconds) domElements.seconds.textContent = seconds; | |
| // Formato compacto para el contador peque帽o | |
| if (domElements.sorteoCountdown) { | |
| domElements.sorteoCountdown.innerHTML = `<span>${days}d ${hours}h ${minutes}m</span>`; | |
| } | |
| // Continuar actualizando | |
| if (difference > 0) { | |
| setTimeout(updateCountdown, 1000); | |
| } | |
| } | |
| // Iniciar cuenta regresiva | |
| updateCountdown(); | |
| } | |
| // Funci贸n para inicializar modales | |
| function initModals() { | |
| // Modal de login | |
| if (domElements.loginBtn && domElements.loginModal) { | |
| // Abrir modal | |
| domElements.loginBtn.addEventListener('click', () => { | |
| domElements.loginModal.classList.add('active'); | |
| }); | |
| // Tambi茅n abrir con el bot贸n de registro | |
| if (domElements.registerBtn) { | |
| domElements.registerBtn.addEventListener('click', () => { | |
| domElements.loginModal.classList.add('active'); | |
| }); | |
| } | |
| // Cerrar modal | |
| if (domElements.closeModal) { | |
| domElements.closeModal.addEventListener('click', () => { | |
| domElements.loginModal.classList.remove('active'); | |
| }); | |
| } | |
| // Cerrar al hacer clic fuera del contenido | |
| domElements.loginModal.addEventListener('click', (e) => { | |
| if (e.target === domElements.loginModal) { | |
| domElements.loginModal.classList.remove('active'); | |
| } | |
| }); | |
| // Simulaci贸n de autenticaci贸n biom茅trica | |
| if (domElements.biometricLogin) { | |
| domElements.biometricLogin.addEventListener('click', () => { | |
| const scannerCircle = document.querySelector('.scanner-circle'); | |
| scannerCircle.classList.add('scanning'); | |
| domElements.biometricLogin.disabled = true; | |
| domElements.biometricLogin.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Escaneando...'; | |
| // Simular proceso de escaneo | |
| setTimeout(() => { | |
| scannerCircle.classList.remove('scanning'); | |
| domElements.biometricLogin.disabled = false; | |
| domElements.biometricLogin.innerHTML = '<i class="fas fa-fingerprint"></i> Autenticar'; | |
| // Cerrar modal | |
| domElements.loginModal.classList.remove('active'); | |
| // Mostrar notificaci贸n de 茅xito | |
| showNotification({ | |
| type: 'success', | |
| title: '隆Autenticaci贸n exitosa!', | |
| message: 'Bienvenido de nuevo, Usuario' | |
| }); | |
| // Simulaci贸n de usuario logueado | |
| if (domElements.loginBtn) { | |
| domElements.loginBtn.innerHTML = '<i class="fas fa-user-circle"></i> Mi Cuenta'; | |
| } | |
| }, 3000); | |
| }); | |
| } | |
| } | |
| // Modal de aprendizaje | |
| if (domElements.learnMoreBtn) { | |
| domElements.learnMoreBtn.addEventListener('click', () => { | |
| showNotification({ | |
| type: 'info', | |
| title: 'Video explicativo', | |
| message: 'El video tutorial se est谩 cargando...' | |
| }); | |
| // Simular carga de video | |
| setTimeout(() => { | |
| const targetSection = document.getElementById('impacto'); | |
| // Cambiar a la secci贸n de impacto | |
| domElements.sections.forEach(section => { | |
| section.classList.remove('section--active'); | |
| }); | |
| targetSection.classList.add('section--active'); | |
| // Actualizar navegaci贸n | |
| domElements.navLinks.forEach(link => { | |
| link.classList.remove('active'); | |
| if (link.getAttribute('href') === '#impacto') { | |
| link.classList.add('active'); | |
| } | |
| }); | |
| // Scroll al inicio de la secci贸n | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| showNotification({ | |
| type: 'success', | |
| title: 'Conoce nuestro impacto', | |
| message: 'Descubre c贸mo estamos transformando Argentina' | |
| }); | |
| }, 1500); | |
| }); | |
| } | |
| } | |
| // Funci贸n para inicializar la calculadora de probabilidades | |
| function initProbabilityCalculator() { | |
| if (!domElements.userCategory) return; | |
| // Actualizar probabilidad al cambiar la categor铆a | |
| domElements.userCategory.addEventListener('change', updateProbability); | |
| // Actualizar inicialmente | |
| updateProbability(); | |
| function updateProbability() { | |
| const category = domElements.userCategory.value; | |
| let probability, boost; | |
| switch (category) { | |
| case 'jubilado': | |
| probability = '1 en 4,608'; | |
| boost = '70% mayor que usuarios generales'; | |
| break; | |
| case 'vulnerable': | |
| probability = '1 en 9,790'; | |
| boost = '20% mayor que usuarios generales'; | |
| break; | |
| case 'general': | |
| probability = '1 en 15,658'; | |
| boost = '0%'; | |
| break; | |
| default: | |
| probability = '1 en 12,000'; | |
| boost = 'est谩ndar'; | |
| } | |
| // Actualizar en la interfaz | |
| const probabilityNumber = document.querySelector('.probability-number'); | |
| const probabilityBoost = document.querySelector('.probability-boost'); | |
| if (probabilityNumber) { | |
| probabilityNumber.textContent = probability; | |
| } | |
| if (probabilityBoost) { | |
| probabilityBoost.innerHTML = category !== 'general' | |
| ? `<i class="fas fa-arrow-up"></i> ${boost}` | |
| : `<i class="fas fa-equals"></i> Probabilidad est谩ndar`; | |
| } | |
| } | |
| } | |
| // Funci贸n para inicializar funcionalidades del marketplace | |
| function initMarketplace() { | |
| // Filtros del marketplace | |
| const filterTags = document.querySelectorAll('.filter-tag'); | |
| if (filterTags) { | |
| filterTags.forEach(tag => { | |
| tag.addEventListener('click', () => { | |
| // Eliminar la clase active de todos los filtros | |
| filterTags.forEach(t => t.classList.remove('active')); | |
| // Agregar la clase active al filtro seleccionado | |
| tag.classList.add('active'); | |
| // Filtrar productos (simulado) | |
| showNotification({ | |
| type: 'info', | |
| title: 'Filtro aplicado', | |
| message: `Mostrando productos: ${tag.textContent}` | |
| }); | |
| }); | |
| }); | |
| } | |
| // Acciones de productos | |
| const productBtns = document.querySelectorAll('.product-card__actions .btn'); | |
| if (productBtns) { | |
| productBtns.forEach(btn => { | |
| btn.addEventListener('click', (e) => { | |
| const action = btn.textContent.trim(); | |
| const productName = btn.closest('.product-card').querySelector('h4').textContent; | |
| showNotification({ | |
| type: 'success', | |
| title: `Acci贸n: ${action}`, | |
| message: `Has seleccionado: ${productName}` | |
| }); | |
| }); | |
| }); | |
| } | |
| // B煤squeda en el marketplace | |
| const searchBtn = document.querySelector('.search-btn'); | |
| if (searchBtn) { | |
| searchBtn.addEventListener('click', () => { | |
| const searchInput = document.querySelector('.search-input'); | |
| if (searchInput && searchInput.value.trim()) { | |
| showNotification({ | |
| type: 'info', | |
| title: 'B煤squeda inteligente', | |
| message: `Buscando: "${searchInput.value}"` | |
| }); | |
| } else { | |
| showNotification({ | |
| type: 'warning', | |
| title: 'B煤squeda vac铆a', | |
| message: 'Ingresa un t茅rmino para buscar' | |
| }); | |
| } | |
| }); | |
| } | |
| } | |
| // Funci贸n para inicializar funcionalidades del DAO | |
| function initDAO() { | |
| // Botones de votaci贸n | |
| const voteButtons = document.querySelectorAll('.proposal-actions .btn'); | |
| if (voteButtons) { | |
| voteButtons.forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| const isInFavor = btn.textContent.includes('A Favor'); | |
| const proposalTitle = btn.closest('.proposal-card').querySelector('h4').textContent; | |
| // Deshabilitar botones de votaci贸n para esa propuesta | |
| const buttons = btn.closest('.proposal-actions').querySelectorAll('.btn'); | |
| buttons.forEach(b => { | |
| b.disabled = true; | |
| b.classList.add('btn--disabled'); | |
| }); | |
| // Actualizar barra de votaci贸n (simulado) | |
| const voteBar = btn.closest('.proposal-card').querySelector( | |
| isInFavor ? '.vote-option--for .vote-fill' : '.vote-option--against .vote-fill' | |
| ); | |
| if (voteBar) { | |
| const currentWidth = parseFloat(voteBar.style.width); | |
| voteBar.style.width = (currentWidth + 2) + '%'; | |
| // Actualizar porcentaje | |
| const percentageElem = btn.closest('.proposal-card').querySelector( | |
| isInFavor ? '.vote-option--for .vote-percentage' : '.vote-option--against .vote-percentage' | |
| ); | |
| if (percentageElem) { | |
| const currentPercentage = parseInt(percentageElem.textContent); | |
| percentageElem.textContent = (currentPercentage + 2) + '%'; | |
| // Actualizar porcentaje opuesto | |
| const oppositeElem = btn.closest('.proposal-card').querySelector( | |
| isInFavor ? '.vote-option--against .vote-percentage' : '.vote-option--for .vote-percentage' | |
| ); | |
| if (oppositeElem) { | |
| const oppositePercentage = parseInt(oppositeElem.textContent); | |
| oppositeElem.textContent = (oppositePercentage - 2) + '%'; | |
| // Actualizar barra opuesta | |
| const oppositeBar = btn.closest('.proposal-card').querySelector( | |
| isInFavor ? '.vote-option--against .vote-fill' : '.vote-option--for .vote-fill' | |
| ); | |
| if (oppositeBar) { | |
| const oppositeWidth = parseFloat(oppositeBar.style.width); | |
| oppositeBar.style.width = (oppositeWidth - 2) + '%'; | |
| } | |
| } | |
| } | |
| } | |
| // Mostrar notificaci贸n | |
| showNotification({ | |
| type: 'success', | |
| title: 'Voto registrado', | |
| message: `Has votado ${isInFavor ? 'a favor' : 'en contra'} de: "${proposalTitle}"` | |
| }); | |
| }); | |
| }); | |
| } | |
| } | |
| // Funci贸n para mostrar notificaciones | |
| function showNotification(options) { | |
| if (!domElements.notificationContainer) return; | |
| const { type, title, message } = options; | |
| // Crear elemento de notificaci贸n | |
| const notification = document.createElement('div'); | |
| notification.className = `notification notification--${type}`; | |
| // Iconos seg煤n tipo | |
| let icon; | |
| switch (type) { | |
| case 'success': | |
| icon = 'check-circle'; | |
| break; | |
| case 'error': | |
| icon = 'exclamation-circle'; | |
| break; | |
| case 'warning': | |
| icon = 'exclamation-triangle'; | |
| break; | |
| case 'info': | |
| default: | |
| icon = 'info-circle'; | |
| } | |
| // Estructura de la notificaci贸n | |
| notification.innerHTML = ` | |
| <div class="notification__icon"> | |
| <i class="fas fa-${icon}"></i> | |
| </div> | |
| <div class="notification__content"> | |
| <div class="notification__title">${title}</div> | |
| <div class="notification__message">${message}</div> | |
| </div> | |
| `; | |
| // Agregar al contenedor | |
| domElements.notificationContainer.appendChild(notification); | |
| // Eliminar despu茅s de 5 segundos | |
| setTimeout(() => { | |
| notification.style.opacity = '0'; | |
| notification.style.transform = 'translateX(100%)'; | |
| notification.style.transition = 'all 0.5s ease'; | |
| setTimeout(() => { | |
| notification.remove(); | |
| }, 500); | |
| }, 5000); | |
| } | |
| // Helpers adicionales | |
| // Formateo de n煤meros para pesos argentinos | |
| function formatCurrency(value) { | |
| return new Intl.NumberFormat('es-AR', { | |
| style: 'currency', | |
| currency: 'ARS', | |
| minimumFractionDigits: 0 | |
| }).format(value); | |
| } | |
| // Formateo de n煤meros grandes | |
| function formatNumber(value) { | |
| return new Intl.NumberFormat('es-AR').format(value); | |
| } | |
| // Generar n煤mero aleatorio entre min y max | |
| function getRandomNumber(min, max) { | |
| return Math.floor(Math.random() * (max - min + 1)) + min; | |
| } |