889 lines
33 KiB
JavaScript
889 lines
33 KiB
JavaScript
/**
|
|
* IDE CONSULTORES - SCRIPT INSTITUCIONAL (JS ÚNICO)
|
|
* Maneja includes modulares, tema claro/oscuro, Brújula IDE, modales, catálogo de cursos, filtros y formularios.
|
|
*/
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
initApp();
|
|
});
|
|
|
|
async function initApp() {
|
|
initTheme();
|
|
await loadIncludes();
|
|
initModals();
|
|
/*initBrujulaIDE();*/
|
|
initAcademyCourses();
|
|
initSolucionesFilters();
|
|
initInsightsFeed();
|
|
initContactForm();
|
|
initCareersForm();
|
|
}
|
|
|
|
/* ==========================================================================
|
|
1. Carga Modular de Header y Footer (JS Nativo)
|
|
========================================================================== */
|
|
async function loadIncludes() {
|
|
const headerElem = document.getElementById('site-header');
|
|
const footerElem = document.getElementById('site-footer');
|
|
|
|
try {
|
|
if (headerElem && headerElem.children.length === 0) {
|
|
const headerRes = await fetch('./includes/header.html', { cache: 'no-store' });
|
|
if (headerRes.ok) {
|
|
headerElem.innerHTML = await headerRes.text();
|
|
highlightActiveNavLink();
|
|
attachHeaderEvents();
|
|
} else {
|
|
// ← NUEVO: Si el fetch falla (ej: 404), igual inicializar eventos
|
|
highlightActiveNavLink();
|
|
attachHeaderEvents();
|
|
}
|
|
} else if (headerElem) {
|
|
highlightActiveNavLink();
|
|
attachHeaderEvents();
|
|
}
|
|
|
|
if (footerElem) {
|
|
const footerRes = await fetch('./includes/footer.html', { cache: 'no-store' });
|
|
if (footerRes.ok) {
|
|
footerElem.innerHTML = await footerRes.text();
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.warn('Header modular no disponible:', err);
|
|
// ← NUEVO: Intentar inicializar igual si el header ya tiene contenido estático
|
|
if (headerElem && headerElem.children.length > 0) {
|
|
highlightActiveNavLink();
|
|
attachHeaderEvents();
|
|
}
|
|
}
|
|
}
|
|
|
|
function highlightActiveNavLink() {
|
|
const currentPath = window.location.pathname;
|
|
const navLinks = document.querySelectorAll('.nav-link');
|
|
|
|
navLinks.forEach(link => {
|
|
const href = link.getAttribute('href');
|
|
if (!href) return;
|
|
|
|
// Comparación de página activa
|
|
if (
|
|
(currentPath === '/' || currentPath.endsWith('index.html')) && (href === '/' || href === 'index.html' || href === './') ||
|
|
(currentPath.includes(href) && href !== '/' && href !== 'index.html')
|
|
) {
|
|
link.classList.add('active');
|
|
} else {
|
|
link.classList.remove('active');
|
|
}
|
|
});
|
|
}
|
|
|
|
function attachHeaderEvents() {
|
|
// Theme toggle
|
|
const themeToggle = document.getElementById('theme-toggle-btn');
|
|
if (themeToggle) {
|
|
const newThemeToggle = themeToggle.cloneNode(true);
|
|
themeToggle.parentNode.replaceChild(newThemeToggle, themeToggle);
|
|
newThemeToggle.addEventListener('click', toggleTheme);
|
|
}
|
|
|
|
const drawer = document.getElementById('mobile-menu-drawer');
|
|
const overlay = document.getElementById('mobile-menu-overlay');
|
|
|
|
function openDrawer() {
|
|
if (!drawer) return;
|
|
drawer.classList.add('is-open');
|
|
drawer.setAttribute('aria-hidden', 'false');
|
|
if (overlay) overlay.classList.add('is-open');
|
|
document.body.style.overflow = 'hidden'; // evita scroll del fondo
|
|
const btn = document.getElementById('mobile-menu-btn');
|
|
if (btn) btn.setAttribute('aria-expanded', 'true');
|
|
}
|
|
|
|
function closeDrawer() {
|
|
if (!drawer) return;
|
|
drawer.classList.remove('is-open');
|
|
drawer.setAttribute('aria-hidden', 'true');
|
|
if (overlay) overlay.classList.remove('is-open');
|
|
document.body.style.overflow = '';
|
|
const btn = document.getElementById('mobile-menu-btn');
|
|
if (btn) btn.setAttribute('aria-expanded', 'false');
|
|
}
|
|
|
|
// Botón hamburguesa abre
|
|
document.getElementById('mobile-menu-btn')
|
|
?.addEventListener('click', openDrawer);
|
|
|
|
// Botón X dentro del drawer cierra
|
|
document.getElementById('drawer-close-btn')
|
|
?.addEventListener('click', closeDrawer);
|
|
|
|
// Clic en overlay cierra
|
|
if (overlay) overlay.addEventListener('click', closeDrawer);
|
|
|
|
// Clic en cualquier link del drawer cierra
|
|
drawer?.querySelectorAll('.nav-link').forEach(link => {
|
|
link.addEventListener('click', closeDrawer);
|
|
});
|
|
|
|
// Tecla ESC cierra
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') closeDrawer();
|
|
});
|
|
|
|
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
|
|
toggleLogoTheme(currentTheme);
|
|
updateThemeIcon(currentTheme);
|
|
}
|
|
|
|
/* ==========================================================================
|
|
2. Selector de Modo Claro / Modo Oscuro con Persistencia
|
|
========================================================================== */
|
|
function initTheme() {
|
|
const savedTheme = localStorage.getItem('ide_theme') || 'light';
|
|
document.documentElement.setAttribute('data-theme', savedTheme);
|
|
updateThemeIcon(savedTheme);
|
|
toggleLogoTheme(savedTheme);
|
|
}
|
|
|
|
function toggleTheme() {
|
|
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
|
|
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
|
document.documentElement.setAttribute('data-theme', newTheme);
|
|
localStorage.setItem('ide_theme', newTheme);
|
|
updateThemeIcon(newTheme);
|
|
toggleLogoTheme(newTheme);
|
|
const themeBtns = document.querySelectorAll('#theme-toggle-btn');
|
|
themeBtns.forEach(btn => {
|
|
btn.setAttribute('aria-label', newTheme === 'dark' ? 'Cambiar a modo claro' : 'Cambiar a modo oscuro');
|
|
});
|
|
}
|
|
|
|
function updateThemeIcon(theme) {
|
|
const themeBtns = document.querySelectorAll('#theme-toggle-btn');
|
|
themeBtns.forEach(btn => {
|
|
btn.setAttribute('aria-label', theme === 'dark' ? 'Cambiar a modo claro' : 'Cambiar a modo oscuro');
|
|
});
|
|
}
|
|
|
|
function toggleLogoTheme(theme) {
|
|
const logoLight = document.querySelector('.logo-light-only');
|
|
const logoDark = document.querySelector('.logo-dark-only');
|
|
|
|
if (logoLight && logoDark) {
|
|
if (theme === 'dark') {
|
|
logoLight.style.display = 'none';
|
|
logoDark.style.display = 'block';
|
|
} else {
|
|
logoLight.style.display = 'block';
|
|
logoDark.style.display = 'none';
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ==========================================================================
|
|
4. Sistema de Modales (Pop-ups con Cierre por Clic Externo y ESC)
|
|
========================================================================== */
|
|
function initModals() {
|
|
const modalBackdrops = document.querySelectorAll('.modal-backdrop');
|
|
|
|
modalBackdrops.forEach(backdrop => {
|
|
// Cerrar al hacer clic en el backdrop (fuera de la ventana)
|
|
backdrop.addEventListener('click', (e) => {
|
|
if (e.target === backdrop) {
|
|
closeModal(backdrop.id);
|
|
}
|
|
});
|
|
|
|
// Botones de cierre interno
|
|
const closeBtns = backdrop.querySelectorAll('.modal-close-btn, [data-close-modal]');
|
|
closeBtns.forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
closeModal(backdrop.id);
|
|
});
|
|
});
|
|
});
|
|
|
|
// Cerrar con tecla ESC
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
const activeModal = document.querySelector('.modal-backdrop.is-active');
|
|
if (activeModal) {
|
|
closeModal(activeModal.id);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Triggers de modales genéricos en páginas (ej: desafíos)
|
|
document.querySelectorAll('[data-open-modal]').forEach(trigger => {
|
|
trigger.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
const modalId = trigger.getAttribute('data-open-modal');
|
|
openModal(modalId);
|
|
});
|
|
});
|
|
}
|
|
|
|
function openModal(modalId) {
|
|
const modal = document.getElementById(modalId);
|
|
if (modal) {
|
|
modal.classList.add('is-active');
|
|
document.body.style.overflow = 'hidden'; // Evita scroll de fondo
|
|
}
|
|
}
|
|
|
|
function closeModal(modalId) {
|
|
const modal = document.getElementById(modalId);
|
|
if (modal) {
|
|
modal.classList.remove('is-active');
|
|
document.body.style.overflow = '';
|
|
}
|
|
}
|
|
|
|
/* ================================================================
|
|
JS QUIZ
|
|
================================================================ */
|
|
|
|
(function () {
|
|
// ----- FLUJO DE NAVEGACIÓN (Opción B) -----
|
|
const FLOW = {
|
|
1: { desafio: '2a', objetivo: '2b', solucion: '2c', conocimiento: '2d' },
|
|
'2a': 3, '2b': 3, '2c': 3, '2d': 3,
|
|
3: 4,
|
|
4: 'result'
|
|
};
|
|
|
|
// ----- MAPEO DE RESULTADOS (Opción B) -----
|
|
function buildResult(answers) {
|
|
const p1 = answers[1];
|
|
const p2 = answers['2a'] || answers['2b'] || answers['2c'] || answers['2d'];
|
|
const p3 = answers[3];
|
|
|
|
// Perfil 4 · Requisito exigido
|
|
if (p3 === 'requisito' || p2 === 'iso' || p2 === 'iso-form') {
|
|
return {
|
|
title: 'La certificación puede ser el punto de partida.',
|
|
body: 'Comprendemos que tenés un requisito externo. En IDE no trabajamos para cumplir auditorías: trabajamos para que el sistema refleje cómo funciona tu organización y contribuya a gestionarla mejor.',
|
|
chips: ['IDE Excellence', 'ISO 9001 / 14001 / 45001', 'Sistemas de gestión'],
|
|
cta: 'Ver soluciones Excellence',
|
|
url: 'soluciones.html'
|
|
};
|
|
}
|
|
|
|
// Perfil 5 · Conocimiento o formación
|
|
if (p1 === 'conocimiento') {
|
|
const map = {
|
|
'iso-form': { chips: ['Auditoría interna', 'ISO 9001', 'Mejora continua'], extra: 'IDE Excellence' },
|
|
'pm-form': { chips: ['Gestión de proyectos', 'Metodologías ágiles', 'PMP'], extra: 'IDE Project' },
|
|
'liderazgo-form': { chips: ['Liderazgo', 'Cambio organizacional', 'Cultura'], extra: 'IDE Academy' },
|
|
'ia-form': { chips: ['IA aplicada', 'Transformación digital', 'Automatización'], extra: 'IDE Digital' }
|
|
};
|
|
const m = map[p2] || { chips: ['Formación', 'Desarrollo', 'Academy'], extra: 'IDE Academy' };
|
|
return {
|
|
title: 'Desarrollamos las capacidades que hacen posible la transformación.',
|
|
body: 'IDE Academy diseña programas de formación alineados con los desafíos reales de las organizaciones. No dictamos cursos estándar: trabajamos desde el contexto de cada equipo.',
|
|
chips: [...m.chips, m.extra],
|
|
cta: 'Conocer IDE Academy',
|
|
url: 'academy.html'
|
|
};
|
|
}
|
|
|
|
// Perfil 3 · Sabe exactamente qué necesita
|
|
if (p1 === 'solucion') {
|
|
const map = {
|
|
iso: {
|
|
title: 'Respuesta concreta. Y algo más.',
|
|
chips: ['ISO 9001', 'ISO 14001', 'IDE Excellence'],
|
|
cta: 'Ver soluciones ISO',
|
|
url: 'soluciones.html',
|
|
body: 'Sí, implementamos y acompañamos certificaciones ISO. Y creemos que un sistema de gestión debe reflejar cómo funciona tu organización, no solo superar una auditoría.'
|
|
},
|
|
pmo: {
|
|
title: 'Proyectos que llegan a destino.',
|
|
chips: ['PMO', 'Gestión de proyectos', 'IDE Project'],
|
|
cta: 'Ver soluciones Project',
|
|
url: 'soluciones.html',
|
|
body: 'Diseñamos PMOs y acompañamos la dirección de proyectos para que se entreguen en tiempo, costo y con los resultados esperados.'
|
|
},
|
|
formacion: {
|
|
title: 'Formación desde el contexto real.',
|
|
chips: ['In Company', 'Capacitación', 'IDE Academy'],
|
|
cta: 'Ver IDE Academy',
|
|
url: 'academy.html',
|
|
body: 'Programas de formación diseñados para tu organización, sus desafíos y las capacidades que necesita desarrollar.'
|
|
},
|
|
'ia-digital': {
|
|
title: 'Tecnología con propósito.',
|
|
chips: ['Transformación digital', 'IA aplicada', 'IDE Digital'],
|
|
cta: 'Ver soluciones Digital',
|
|
url: 'soluciones.html',
|
|
body: 'Te ayudamos a identificar dónde la IA y la digitalización generan valor real, y acompañamos su implementación de principio a fin.'
|
|
}
|
|
};
|
|
const m = map[p2] || {
|
|
title: 'Encontramos lo que buscás.',
|
|
chips: ['Soluciones concretas', 'Ecosistema IDE'],
|
|
cta: 'Ver soluciones',
|
|
url: 'soluciones.html',
|
|
body: 'Tenemos la respuesta concreta que buscás. Y una mirada que asegura que esa solución genere valor en el conjunto de tu organización.'
|
|
};
|
|
return { icon: './assets/iconos/engranaje_32.svg', profile: 'Perfil · Solución concreta', ...m };
|
|
}
|
|
|
|
// Perfil 2 · Sabe qué quiere lograr
|
|
if (p1 === 'objetivo') {
|
|
const map = {
|
|
'mejorar-gestion': { chips: ['IDE Excellence', 'Mejora de procesos'], body: 'Entendemos dónde querés llegar. Antes de proponer una solución, comprendemos tu operación para intervenir donde hay mayor impacto.' },
|
|
'profesionalizar-proyectos':{ chips: ['IDE Project', 'PMO'], body: 'Traducimos tu objetivo en una estructura de gestión de proyectos adecuada a tu contexto, sin sobreingeniería.' },
|
|
'desarrollar-equipo': { chips: ['IDE Academy', 'Formación In Company'], body: 'Desarrollamos capacidades alineadas con los desafíos reales de tu organización. La formación parte del contexto, no de un catálogo estándar.' },
|
|
'transformar-digital': { chips: ['IDE Digital', 'IA aplicada'], body: 'Empezamos por entender tu organización para identificar dónde la tecnología realmente agrega valor, y avanzamos desde ahí.' }
|
|
};
|
|
const m = map[p2] || { chips: ['Ecosistema IDE'], body: 'Entendemos dónde querés llegar. Comprendemos el sistema para ayudarte a lograrlo.' };
|
|
return {
|
|
title: 'Entendemos dónde querés llegar. Te ayudamos a definir cómo.',
|
|
body: m.body,
|
|
chips: m.chips,
|
|
cta: 'Explorar por desafío',
|
|
url: 'desafios.html'
|
|
};
|
|
}
|
|
|
|
// Perfil 1 · Desafío sin solución definida
|
|
const mapD = {
|
|
gestion: { chips: ['Procesos', 'Gestión', 'IDE Excellence'] },
|
|
proyectos: { chips: ['Proyectos', 'PMO', 'IDE Project'] },
|
|
personas: { chips: ['Capacidades', 'Equipo', 'IDE Academy'] },
|
|
tecnologia: { chips: ['IA', 'Digital', 'IDE Digital'] },
|
|
nosabe: { chips: ['Diagnóstico sistémico', 'Ecosistema IDE'] }
|
|
};
|
|
const md = mapD[p2] || mapD.nosabe;
|
|
return {
|
|
title: 'No necesitás tener la respuesta para empezar.',
|
|
body: 'Empezamos por comprender tu situación, no por ofrecerte una solución predeterminada. Eso diferencia una intervención puntual de una transformación real.',
|
|
chips: md.chips,
|
|
cta: 'Explorar desafíos',
|
|
url: 'desafios.html'
|
|
};
|
|
}
|
|
|
|
// ----- ESTADO -----
|
|
let currentStep = 1;
|
|
let stepHistory = [];
|
|
let answers = {};
|
|
const TOTAL = 4;
|
|
|
|
const container = document.getElementById('quiz-interactive-app');
|
|
if (!container) return;
|
|
|
|
// ----- FUNCIONES -----
|
|
function showStep(id) {
|
|
const steps = container.querySelectorAll('.quiz-step');
|
|
steps.forEach(s => s.classList.remove('active'));
|
|
|
|
const el = document.getElementById('step-' + id);
|
|
if (el) el.classList.add('active');
|
|
|
|
updateProgress(id);
|
|
updateIndicator(id);
|
|
}
|
|
|
|
function updateProgress(id) {
|
|
const fill = document.getElementById('quiz-progress-fill');
|
|
if (!fill) return;
|
|
|
|
let n = 1;
|
|
if (id === 'result') n = 4;
|
|
else if (['2a', '2b', '2c', '2d'].includes(String(id))) n = 2;
|
|
else n = parseInt(id) || 1;
|
|
|
|
fill.style.width = (n / TOTAL * 100) + '%';
|
|
}
|
|
|
|
function updateIndicator(id) {
|
|
const label = document.getElementById('quiz-step-indicator');
|
|
if (!label) return;
|
|
|
|
let text = '';
|
|
if (id === 'result') text = '¡Orientación lista!';
|
|
else if (['2a', '2b', '2c', '2d'].includes(String(id))) text = 'Paso 2 de 4';
|
|
else text = 'Paso ' + id + ' de 4';
|
|
|
|
label.textContent = text;
|
|
}
|
|
|
|
function renderResult(ans) {
|
|
const r = buildResult(ans);
|
|
|
|
document.getElementById('resultTitle').textContent = r.title;
|
|
document.getElementById('resultBody').textContent = r.body;
|
|
|
|
const chipsContainer = document.getElementById('resultChips');
|
|
chipsContainer.innerHTML = r.chips.map(c =>
|
|
`<span class="result-chip">${c}</span>`
|
|
).join('');
|
|
|
|
const cta = document.getElementById('resultCTA');
|
|
cta.textContent = r.cta;
|
|
cta.href = r.url;
|
|
|
|
showStep('result');
|
|
}
|
|
|
|
function handleOption(btn) {
|
|
const step = btn.dataset.step;
|
|
const val = btn.dataset.val;
|
|
|
|
// Deseleccionar otras opciones del mismo paso
|
|
const parent = btn.closest('.quiz-options-grid');
|
|
if (parent) {
|
|
parent.querySelectorAll('.quiz-option-card').forEach(b => b.classList.remove('selected'));
|
|
}
|
|
btn.classList.add('selected');
|
|
|
|
answers[step] = val;
|
|
stepHistory.push(step);
|
|
|
|
const next = FLOW[step];
|
|
if (!next) return;
|
|
|
|
if (next === 'result') {
|
|
renderResult(answers);
|
|
return;
|
|
}
|
|
|
|
const nextId = typeof next === 'object' ? (next[val] || '2a') : next;
|
|
showStep(nextId);
|
|
}
|
|
|
|
// ----- FUNCIONES GLOBALES (para onclick en HTML) -----
|
|
window.goBack = function () {
|
|
if (!stepHistory.length) return;
|
|
const prev = stepHistory.pop();
|
|
delete answers[prev];
|
|
|
|
const last = stepHistory[stepHistory.length - 1] || 1;
|
|
showStep(last);
|
|
};
|
|
|
|
window.restartQuiz = function () {
|
|
answers = {};
|
|
stepHistory = [];
|
|
container.querySelectorAll('.quiz-option-card').forEach(b => b.classList.remove('selected'));
|
|
showStep(1);
|
|
};
|
|
|
|
// ----- INIT -----
|
|
function initQuiz() {
|
|
// Eventos en las cards de opción
|
|
container.querySelectorAll('.quiz-option-card').forEach(btn => {
|
|
btn.addEventListener('click', function () {
|
|
handleOption(this);
|
|
});
|
|
});
|
|
|
|
showStep(1);
|
|
}
|
|
|
|
// Ejecutar al cargar el DOM
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initQuiz);
|
|
} else {
|
|
initQuiz();
|
|
}
|
|
})();
|
|
|
|
/* ==========================================================================
|
|
6. Carga Dinámica de Cursos en IDE Academy (cursos.json)
|
|
========================================================================== */
|
|
let allCourses = [];
|
|
|
|
async function initAcademyCourses() {
|
|
const container = document.getElementById('academy-courses-container');
|
|
if (!container) return;
|
|
|
|
try {
|
|
const res = await fetch('/data/cursos.json');
|
|
if (!res.ok) throw new Error('No se pudo cargar cursos.json');
|
|
allCourses = await res.json();
|
|
renderCourseCards(allCourses, container);
|
|
} catch (err) {
|
|
console.warn('Cargando cursos con datos de respaldo.');
|
|
allCourses = getFallbackCourses();
|
|
renderCourseCards(allCourses, container);
|
|
}
|
|
}
|
|
|
|
function renderCourseCards(courses, container) {
|
|
container.innerHTML = '';
|
|
|
|
courses.forEach(course => {
|
|
const card = document.createElement('div');
|
|
card.className = 'card';
|
|
card.innerHTML = `
|
|
<div class="ecosystem-badge badge-academy" style="margin-bottom: 0.8rem;">${course.categoria}</div>
|
|
<h3 style="font-size: 1.15rem; margin-bottom: 0.6rem;">${course.titulo}</h3>
|
|
<p style="font-size: 0.88rem; color: var(--text-muted); margin-bottom: 1.25rem; line-height: 1.5;">${course.descripcion_corta}</p>
|
|
|
|
<div style="font-size: 0.82rem; color: var(--text-body); display: flex; flex-direction: column; gap: 0.35rem; margin-bottom: 1.5rem; border-top: 1px solid var(--border-color); padding-top: 0.85rem;">
|
|
<div><strong>Modalidad:</strong> ${course.modalidad}</div>
|
|
<div><strong>Duración:</strong> ${course.duracion}</div>
|
|
<div><strong>Próxima fecha:</strong> ${course.proxima_fecha}</div>
|
|
</div>
|
|
|
|
<button class="btn btn-outline btn-sm w-full" style="width: 100%;" onclick="openCourseModal('${course.id}')">
|
|
Ver Ficha Técnica y Programa
|
|
</button>
|
|
`;
|
|
container.appendChild(card);
|
|
});
|
|
}
|
|
|
|
// Modal dinámico de cursos
|
|
window.openCourseModal = function (courseId) {
|
|
const course = allCourses.find(c => c.id === courseId);
|
|
if (!course) return;
|
|
|
|
const titleElem = document.getElementById('modal-course-title');
|
|
const catElem = document.getElementById('modal-course-category');
|
|
const detailsElem = document.getElementById('modal-course-details');
|
|
const ctaElem = document.getElementById('modal-course-cta');
|
|
|
|
if (titleElem) titleElem.innerText = course.titulo;
|
|
if (catElem) catElem.innerText = `${course.categoria} • ${course.modalidad} • ${course.duracion}`;
|
|
|
|
if (detailsElem) {
|
|
const objHtml = course.objetivos.map(obj => `<li>${obj}</li>`).join('');
|
|
const temHtml = course.temario.map(tem => `<li>${tem}</li>`).join('');
|
|
|
|
detailsElem.innerHTML = `
|
|
<div style="margin-bottom: 1.5rem;">
|
|
<h4 style="font-size: 1rem; color: var(--ide-primary); margin-bottom: 0.4rem;">Propuesta Formativa</h4>
|
|
<p style="font-size: 0.92rem; color: var(--text-body);">${course.propuesta}</p>
|
|
</div>
|
|
|
|
<div style="margin-bottom: 1.5rem;">
|
|
<h4 style="font-size: 1rem; color: var(--ide-primary); margin-bottom: 0.4rem;">Objetivos del Programa</h4>
|
|
<ul style="padding-left: 1.25rem; font-size: 0.9rem; color: var(--text-body); line-height: 1.6;">
|
|
${objHtml}
|
|
</ul>
|
|
</div>
|
|
|
|
<div style="margin-bottom: 1.5rem;">
|
|
<h4 style="font-size: 1rem; color: var(--ide-primary); margin-bottom: 0.4rem;">Temario Modular</h4>
|
|
<ul style="padding-left: 1.25rem; font-size: 0.9rem; color: var(--text-body); line-height: 1.6;">
|
|
${temHtml}
|
|
</ul>
|
|
</div>
|
|
|
|
<div style="background-color: var(--bg-subtle); padding: 1rem; border-radius: var(--radius-sm); font-size: 0.88rem; margin-bottom: 1.5rem;">
|
|
<p><strong>Cuerpo Docente:</strong> ${course.docente}</p>
|
|
<p><strong>Impacto Esperado:</strong> ${course.resultados_esperados}</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
if (ctaElem) {
|
|
const params = new URLSearchParams({
|
|
origen: 'IDE_Academy',
|
|
busqueda: 'Formación para mi organización',
|
|
curso: course.titulo
|
|
});
|
|
ctaElem.setAttribute('href', `contacto.html?${params.toString()}`);
|
|
}
|
|
|
|
openModal('modal-course-view');
|
|
};
|
|
|
|
function getFallbackCourses() {
|
|
return [
|
|
{
|
|
id: "curso-iso-9001",
|
|
titulo: "Sistemas de Gestión de Calidad (ISO 9001:2015): De la Norma a la Gestión Real",
|
|
categoria: "IDE Excellence & Academy",
|
|
modalidad: "Online sincrónico / In-Company",
|
|
duracion: "32 horas (8 semanas)",
|
|
descripcion_corta: "Aprenda a diseñar, implementar y auditar un SGC que trascienda la mera auditoría y transforme los procesos.",
|
|
propuesta: "Una visión viva y práctica para la toma de decisiones estratégicas.",
|
|
objetivos: ["Comprender la estructura ISO 9001:2015", "Mapear procesos con enfoque de riesgos", "Diseñar KPIs pertinentes"],
|
|
temario: ["Módulo 1: Enfoque a procesos", "Módulo 2: Liderazgo y calidad", "Módulo 3: Auditorías y mejora continua"],
|
|
docente: "Equipo Senior de Consultores IDE Excellence.",
|
|
resultados_esperados: "Capacidad de liderar un SGC con valor real de negocio.",
|
|
proxima_fecha: "Octubre 2026"
|
|
}
|
|
];
|
|
}
|
|
|
|
/* ==========================================================================
|
|
7. Filtros Dinámicos en la Página de Soluciones
|
|
========================================================================== */
|
|
function initSolucionesFilters() {
|
|
const filterBtns = document.querySelectorAll('.soluciones-filter-btn');
|
|
const solutionCards = document.querySelectorAll('.solution-card');
|
|
|
|
console.log('🔍 Filtros encontrados:', filterBtns.length);
|
|
console.log('📦 Tarjetas encontradas:', solutionCards.length);
|
|
|
|
if (!filterBtns.length) {
|
|
console.warn('⚠️ No se encontraron botones de filtro');
|
|
return;
|
|
}
|
|
|
|
filterBtns.forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
filterBtns.forEach(b => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
|
|
const filter = btn.getAttribute('data-filter');
|
|
console.log('🎯 Filtro seleccionado:', filter);
|
|
|
|
solutionCards.forEach(card => {
|
|
const cat = card.getAttribute('data-category');
|
|
console.log(` 📌 Tarjeta: ${cat} → ${filter === 'all' || cat === filter ? 'MOSTRAR' : 'OCULTAR'}`);
|
|
|
|
if (filter === 'all' || cat === filter) {
|
|
card.classList.remove('hidden');
|
|
} else {
|
|
card.classList.add('hidden');
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ==========================================================================
|
|
8. Feed de Noticias Insights (WordPress REST API + Respaldo de 3 Artículos)
|
|
========================================================================== */
|
|
async function initInsightsFeed() {
|
|
const container = document.getElementById('insights-feed-container');
|
|
if (!container) return;
|
|
|
|
const mockArticles = [
|
|
{
|
|
titulo: "Por qué optimizar una parte de la organización puede desestabilizar el todo",
|
|
extracto: "Enfoque sistémico: cuando las áreas buscan sus propios objetivos sin comprender las relaciones cruzadas, las soluciones aisladas crean nuevos cuellos de botella.",
|
|
fecha: "28 de Agosto, 2026",
|
|
categoria: "Pensamiento Sistémico",
|
|
enlace: "https://blog.ideconsultores.com.ar"
|
|
},
|
|
{
|
|
titulo: "ISO 9001:2015: Cómo evitar que la certificación se convierta en una carga burocrática",
|
|
extracto: "Claves prácticas para que los sistemas de gestión de calidad sean herramientas útiles para la toma de decisiones y no meras carpetas para superar una auditoría anual.",
|
|
fecha: "15 de Agosto, 2026",
|
|
categoria: "Gestión & Calidad",
|
|
enlace: "https://blog.ideconsultores.com.ar"
|
|
},
|
|
{
|
|
titulo: "Inteligencia Artificial en procesos: Automatizar con propósito, no por moda",
|
|
extracto: "Antes de implementar herramientas de IA generativa, es indispensable diagnosticar la madurez de los procesos y las capacidades del equipo humano.",
|
|
fecha: "02 de Agosto, 2026",
|
|
categoria: "Transformación Digital",
|
|
enlace: "https://blog.ideconsultores.com.ar"
|
|
}
|
|
];
|
|
|
|
try {
|
|
// Intento de conexión con la API de WordPress
|
|
const res = await fetch('https://blog.ideconsultores.com.ar/wp-json/wp/v2/posts?_embed&per_page=3', {
|
|
method: 'GET',
|
|
headers: { 'Accept': 'application/json' }
|
|
});
|
|
|
|
if (res.ok) {
|
|
const posts = await res.json();
|
|
if (posts && posts.length > 0) {
|
|
renderWpPosts(posts, container);
|
|
return;
|
|
}
|
|
}
|
|
renderMockArticles(mockArticles, container);
|
|
} catch (e) {
|
|
// Si WordPress no está disponible o CORS está en configuración, se muestran los 3 artículos
|
|
renderMockArticles(mockArticles, container);
|
|
}
|
|
}
|
|
|
|
function renderMockArticles(articles, container) {
|
|
container.innerHTML = articles.map(art => `
|
|
<article class="card" style="display: flex; flex-direction: column; justify-content: space-between;">
|
|
<div>
|
|
<div class="img-placeholder" style="aspect-ratio: 16/9; margin-bottom: 1.25rem; padding: 1.5rem;">
|
|
<div class="img-placeholder-icon">📰</div>
|
|
<div class="img-placeholder-label">Imagen Artículo Blog</div>
|
|
</div>
|
|
<div style="font-size: 0.8rem; font-weight: 700; color: var(--ide-accent); margin-bottom: 0.4rem; text-transform: uppercase;">
|
|
${art.categoria} • <span style="color: var(--text-muted); font-weight: 400;">${art.fecha}</span>
|
|
</div>
|
|
<h3 style="font-size: 1.2rem; margin-bottom: 0.75rem; line-height: 1.35;">${art.titulo}</h3>
|
|
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.55; margin-bottom: 1.5rem;">${art.extracto}</p>
|
|
</div>
|
|
<a href="${art.enlace}" target="_blank" rel="noopener noreferrer" class="btn btn-outline btn-sm" style="align-self: flex-start;">
|
|
Leer artículo completo en el Blog →
|
|
</a>
|
|
</article>
|
|
`).join('');
|
|
}
|
|
|
|
function renderWpPosts(posts, container) {
|
|
container.innerHTML = posts.map(post => {
|
|
const title = post.title?.rendered || 'Artículo';
|
|
const excerpt = post.excerpt?.rendered?.replace(/<[^>]*>?/gm, '').substring(0, 140) + '...' || '';
|
|
const link = post.link || 'https://blog.ideconsultores.com.ar';
|
|
const date = new Date(post.date).toLocaleDateString('es-AR', { day: 'numeric', month: 'long', year: 'numeric' });
|
|
|
|
return `
|
|
<article class="card" style="display: flex; flex-direction: column; justify-content: space-between;">
|
|
<div>
|
|
<div class="img-placeholder" style="aspect-ratio: 16/9; margin-bottom: 1.25rem; padding: 1.5rem;">
|
|
<div class="img-placeholder-icon">📰</div>
|
|
<div class="img-placeholder-label">Imagen Destacada WP</div>
|
|
</div>
|
|
<div style="font-size: 0.8rem; font-weight: 700; color: var(--ide-accent); margin-bottom: 0.4rem;">
|
|
${date}
|
|
</div>
|
|
<h3 style="font-size: 1.2rem; margin-bottom: 0.75rem; line-height: 1.35;">${title}</h3>
|
|
<p style="font-size: 0.9rem; color: var(--text-muted); line-height: 1.55; margin-bottom: 1.5rem;">${excerpt}</p>
|
|
</div>
|
|
<a href="${link}" target="_blank" rel="noopener noreferrer" class="btn btn-outline btn-sm" style="align-self: flex-start;">
|
|
Leer en el Blog de IDE →
|
|
</a>
|
|
</article>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
/* ==========================================================================
|
|
9. Formulario Inteligente de Contacto (Pre-llenado y Envío AJAX)
|
|
========================================================================== */
|
|
function initContactForm() {
|
|
const form = document.getElementById('ide-contact-form');
|
|
if (!form) return;
|
|
|
|
// Prellenado a partir de parámetros URL
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const busquedaParam = urlParams.get('busqueda');
|
|
const origenParam = urlParams.get('origen');
|
|
const cursoParam = urlParams.get('curso');
|
|
const focoParam = urlParams.get('foco');
|
|
const dolorParam = urlParams.get('dolor');
|
|
const recParam = urlParams.get('recomendacion');
|
|
|
|
const selectBusqueda = document.getElementById('contact-busqueda');
|
|
const mensajeArea = document.getElementById('contact-mensaje');
|
|
const origenHidden = document.getElementById('contact-origen');
|
|
|
|
if (origenParam && origenHidden) {
|
|
origenHidden.value = origenParam;
|
|
}
|
|
|
|
if (busquedaParam && selectBusqueda) {
|
|
for (let i = 0; i < selectBusqueda.options.length; i++) {
|
|
if (selectBusqueda.options[i].text.toLowerCase().includes(busquedaParam.toLowerCase()) || selectBusqueda.options[i].value.toLowerCase().includes(busquedaParam.toLowerCase())) {
|
|
selectBusqueda.selectedIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mensajeArea) {
|
|
if (cursoParam) {
|
|
mensajeArea.value = `Hola, me interesa solicitar información detallada sobre el programa: "${cursoParam}" (fechas, aranceles o modalidad In-Company).`;
|
|
} else if (recParam) {
|
|
mensajeArea.value = `Hola, realicé el diagnóstico de la Brújula IDE:\n- Prioridad: ${focoParam || 'No especificada'}\n- Desafío actual: ${dolorParam || 'No especificado'}\n- Orientación sugerida: ${recParam}\n\nQuisiera coordinar una charla para profundizar en nuestro contexto.`;
|
|
}
|
|
}
|
|
|
|
// Envío del formulario
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const alertBox = document.getElementById('contact-form-alert');
|
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
|
|
if (submitBtn) {
|
|
submitBtn.setAttribute('disabled', 'true');
|
|
submitBtn.innerText = 'Enviando mensaje...';
|
|
}
|
|
|
|
const formData = new FormData(form);
|
|
const dataObj = Object.fromEntries(formData.entries());
|
|
|
|
try {
|
|
const res = await fetch('/php/send-mail.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(dataObj)
|
|
});
|
|
|
|
const result = await res.json();
|
|
|
|
if (alertBox) {
|
|
alertBox.className = 'form-alert alert-success';
|
|
alertBox.innerText = result.message || '¡Mensaje recibido! Nos comunicaremos a la brevedad.';
|
|
alertBox.style.display = 'block';
|
|
}
|
|
form.reset();
|
|
} catch (error) {
|
|
if (alertBox) {
|
|
alertBox.className = 'form-alert alert-success';
|
|
alertBox.innerText = '¡Muchas gracias por comunicarte! Tu mensaje ha sido registrado con éxito. Te responderemos pronto a tu casilla de correo.';
|
|
alertBox.style.display = 'block';
|
|
}
|
|
form.reset();
|
|
} finally {
|
|
if (submitBtn) {
|
|
submitBtn.removeAttribute('disabled');
|
|
submitBtn.innerText = 'HABLEMOS';
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/* ==========================================================================
|
|
10. Formulario de Empleo (Trabaja con nosotros)
|
|
========================================================================== */
|
|
function initCareersForm() {
|
|
const form = document.getElementById('ide-careers-form');
|
|
if (!form) return;
|
|
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const alertBox = document.getElementById('careers-form-alert');
|
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
|
|
if (submitBtn) {
|
|
submitBtn.setAttribute('disabled', 'true');
|
|
submitBtn.innerText = 'Enviando postulación...';
|
|
}
|
|
|
|
const formData = new FormData(form);
|
|
const dataObj = Object.fromEntries(formData.entries());
|
|
|
|
try {
|
|
const res = await fetch('/php/send-mail.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(dataObj)
|
|
});
|
|
const result = await res.json();
|
|
|
|
if (alertBox) {
|
|
alertBox.className = 'form-alert alert-success';
|
|
alertBox.innerText = result.message || '¡Postulación recibida! Gracias por tu interés en sumarte a IDE Consultores.';
|
|
alertBox.style.display = 'block';
|
|
}
|
|
form.reset();
|
|
} catch (error) {
|
|
if (alertBox) {
|
|
alertBox.className = 'form-alert alert-success';
|
|
alertBox.innerText = '¡Postulación recibida con éxito! Revisaremos tu perfil en nuestro equipo.';
|
|
alertBox.style.display = 'block';
|
|
}
|
|
form.reset();
|
|
} finally {
|
|
if (submitBtn) {
|
|
submitBtn.removeAttribute('disabled');
|
|
submitBtn.innerText = 'Enviar Postulación';
|
|
}
|
|
}
|
|
});
|
|
} |