/* ============================================================================ SoftSPM - harmonogram z Akademii Wodociągowca Podmienia wiersze tabeli terminów danymi z api/schedule.php. Gdy API nie odpowiada albo nie ma pozycji, statyczne wiersze z HTML-a zostają nietknięte - strona nigdy nie pokazuje pustej tabeli. ========================================================================= */ (function () { 'use strict'; var DICT = { pl: { dateHead: 'Data', webinar: 'Webinar', training: 'Szkolenie', online: 'Online', elearning: 'Online · e-learning', onDemand: 'Na żądanie', signUp: 'Zapisz się →', viewCourse: 'Zobacz kurs →', soldOut: 'Brak miejsc', soon: 'Zapisy wkrótce', note: 'Terminy pobierane na bieżąco z platformy kursowej Akademia Wodociągowca. Zapisy prowadzi Akademia.', plateTitle: 'Terminy i kursy otwarte', heading: 'Najbliższe szkolenia i webinaria', intro: 'Poniżej pozycje otwarte w tej chwili na naszej platformie kursowej. Zapisy prowadzi Akademia Wodociągowca.', locale: 'pl-PL', levels: { BASIC: 'podstawowy', INTERMEDIATE: 'średni', ADVANCED: 'zaawansowany' } }, en: { dateHead: 'Date', webinar: 'Webinar', training: 'Training', online: 'Online', elearning: 'Online · e-learning', onDemand: 'On demand', signUp: 'Sign up →', viewCourse: 'View course →', soldOut: 'Fully booked', soon: 'Registration soon', note: 'Dates are pulled live from our Akademia Wodociagowca course platform, which also handles registration.', plateTitle: 'Open dates and courses', heading: 'Upcoming training and webinars', intro: 'Everything currently open on our course platform. Registration is handled by Akademia Wodociagowca.', locale: 'en-GB', levels: { BASIC: 'basic', INTERMEDIATE: 'intermediate', ADVANCED: 'advanced' } } }; var lang = (document.documentElement.getAttribute('lang') || 'pl').slice(0, 2).toLowerCase(); var t = DICT[lang] || DICT.pl; function el(tag, className, text) { var node = document.createElement(tag); if (className) { node.className = className; } if (text !== undefined && text !== null) { node.textContent = text; } return node; } function formatDate(iso, timezone) { var date = new Date(iso); if (isNaN(date.getTime())) { return null; } var zone = timezone || 'Europe/Warsaw'; var opts = { day: '2-digit', month: '2-digit', year: 'numeric', timeZone: zone }; var timeOpts = { hour: '2-digit', minute: '2-digit', timeZone: zone }; try { return { day: new Intl.DateTimeFormat(t.locale, opts).format(date), hour: new Intl.DateTimeFormat(t.locale, timeOpts).format(date) }; } catch (e) { // Nieznana strefa albo stary silnik - pokazujemy datę bez strefy. return { day: date.toLocaleDateString(t.locale), hour: date.toLocaleTimeString(t.locale) }; } } function actionCell(item) { var cell = el('td', 's-act'); if (item.kind === 'webinar' && item.soldOut) { cell.appendChild(el('span', 'text-muted', t.soldOut)); return cell; } if (item.kind === 'webinar' && item.open === false) { cell.appendChild(el('span', 'text-muted', t.soon)); return cell; } if (!item.url) { cell.appendChild(el('span', 'text-muted', item.kind === 'webinar' ? t.soon : '')); return cell; } var link = el('a', 'sign', item.kind === 'webinar' ? t.signUp : t.viewCourse); link.href = item.url; link.target = '_blank'; link.rel = 'noopener'; cell.appendChild(link); return cell; } function buildRow(item) { var row = document.createElement('tr'); var date = el('td', 's-date'); if (item.kind === 'webinar') { var parts = formatDate(item.startsAt, item.timezone); if (parts) { date.appendChild(document.createTextNode(parts.day)); date.appendChild(el('span', 's-hour', parts.hour)); } else { date.appendChild(el('span', 'tag tag-soon', t.onDemand)); } } else { date.appendChild(el('span', 'tag tag-soon', t.onDemand)); } row.appendChild(date); // textContent, nie innerHTML - tytuły przychodzą z innego systemu. row.appendChild(el('td', 's-topic', item.title)); var form = el('td', 's-form'); form.appendChild(el( 'span', item.kind === 'webinar' ? 'tag tag-outline' : 'tag tag-accent', item.kind === 'webinar' ? t.webinar : t.training )); row.appendChild(form); var place = item.kind === 'webinar' ? t.online : t.elearning; if (item.kind === 'course' && item.level && t.levels[item.level]) { place = t.elearning + ' · ' + t.levels[item.level]; } row.appendChild(el('td', 's-place', place)); row.appendChild(actionCell(item)); return row; } function render(table, items) { var body = table.querySelector('tbody'); if (!body) { return; } var fresh = document.createDocumentFragment(); for (var i = 0; i < items.length; i++) { fresh.appendChild(buildRow(items[i])); } body.innerHTML = ''; body.appendChild(fresh); // Mamy realne daty, więc nagłówek kolumny wraca z "Termin" na "Data". var head = table.querySelector('[data-schedule-datehead]'); if (head) { head.textContent = t.dateHead; } // Przy realnych terminach nagłówki mówiące "ustalamy terminy" przestają // być prawdziwe, więc lecą razem z wierszami. var section = table.closest ? table.closest('section') : null; if (section) { var heading = section.querySelector('[data-schedule-heading]'); if (heading) { heading.textContent = t.heading; } var intro = section.querySelector('[data-schedule-intro]'); if (intro) { intro.textContent = t.intro; } } var plate = table.closest ? table.closest('.plate') : null; var plateTitle = plate ? plate.querySelector('[data-schedule-title]') : null; if (plateTitle) { plateTitle.textContent = t.plateTitle; } var note = plate ? plate.querySelector('[data-schedule-note]') : null; if (note) { note.textContent = t.note + ' '; var link = el('a', null, 'akademiawodociagowca.pl'); link.href = 'https://akademiawodociagowca.pl/'; link.target = '_blank'; link.rel = 'noopener'; note.appendChild(link); } table.setAttribute('data-schedule-state', 'live'); } function boot() { var tables = document.querySelectorAll('table[data-schedule]'); if (!tables.length) { return; } var limit = 0; for (var i = 0; i < tables.length; i++) { limit = Math.max(limit, parseInt(tables[i].getAttribute('data-schedule-limit'), 10) || 12); } fetch('api/schedule.php?limit=' + limit, { credentials: 'same-origin', headers: { 'Accept': 'application/json' } }) .then(function (response) { return response.json(); }) .then(function (data) { if (!data || data.source !== 'api' || !data.items || !data.items.length) { return; } for (var i = 0; i < tables.length; i++) { var own = parseInt(tables[i].getAttribute('data-schedule-limit'), 10) || data.items.length; render(tables[i], data.items.slice(0, own)); } }) .catch(function () { // Cisza jest właściwą reakcją: w tabeli zostają statyczne wiersze. }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); } })();