PageSourceSearch

https://blumenau.sc.gov.br/eficiente/sites/blumenau/javascript/home.js

js blumenau.sc.gov.br collected 2026-09-24 09:31:13 UTC 23,346 bytes, 610 lines download raw bytes

1const GetServicoTemas = async () => {
2    const response = await fetch('/eficiente/sites/blumenau/ajax/servicos.tabs.php');
3    const data = await response.json();
4    return data;
5}
6
7const GetServicoAssuntos = async () => {
8    const response = await fetch('/eficiente/sites/blumenau/ajax/servicos.tema.php?limit=9');
9    const data = await response.json();
10    return data;
11}
12
13const GetNoticiasHome = async () => {
14    const response = await fetch('/eficiente/sites/blumenau/ajax/publicacoes.noticias.php?limit=15');
15    const data = await response.json();
16    return data;
17}
18
19const GetPublicacoesOficiais = async () => {
20    const response = await fetch('/eficiente/sites/blumenau/ajax/publicacoes.oficiais.php?limit=20');
21    const data = await response.json();
22    return data;
23}
24
25const GetBannersHome = async () => {
26    const response = await fetch('/eficiente/sites/blumenau/ajax/publicacoes.banners.php?limit=5');
27    const data = await response.json();
28    return data;
29}
30
31const GetComunicadosHome = async () => {
32    const response = await fetch('/eficiente/sites/blumenau/ajax/publicacoes.comunicados.php?limit=5');
33    const data = await response.json();
34    return data;
35}
36
37const GetBannerSecundarioHome = async () => {
38    const response = await fetch('/eficiente/sites/blumenau/ajax/publicacoes.bannersecundario.php?limit=5');
39    const data = await response.json();
40    return data;
41}
42
43const GetAcessoRapidoHome = async () => {
44    const response = await fetch('/eficiente/sites/blumenau/ajax/publicacoes.acessorapido.php?limit=4');
45    const data = await response.json();
46    return data;
47}
48
49const GetLocaisHome = async () => {
50    const response = await fetch('/eficiente/sites/blumenau/ajax/publicacoes.locais.php?limit=18');
51    const data = await response.json();
52    return data;
53}
54
55const GetSecaoHome = async () => {
56    const response = await fetch('/eficiente/sites/blumenau/ajax/secoes.home.php');
57    const data = await response.json();
58    return data;
59}
60
61const RenderSecaoHome = (data) => {
62    const header = document.querySelector('.tourism-header');
63    if (!header || !data || !data.fields) return;
64
65    const fields = data.fields;
66    const title = fields["Título da seção locais"];
67    const text = fields["Texto da seção locais"];
68    const btnText = fields["Texto botão visitar"];
69    const btnLink = fields["Link botão visitar"];
70
71    if (title) {
72        const h2 = header.querySelector('h2');
73        if (h2) h2.textContent = title;
74    }
75
76    if (text) {
77        const p = header.querySelector('p');
78        if (p) {
79            // Replace newlines or corrupted 'rn' with <br>
80            // Note: Since I fixed funcoes.php, new saves will have real newlines.
81            // If the data is still corrupted with 'rn', we can try to fix it here too.
82            let formattedText = text.replace(/\r\n|\r|\n/g, '<br>');
83            // If the user hasn't re-saved yet, 'rn' might be literal. 
84            // But replacing all 'rn' is dangerous. We'll stick to real newlines for now.
85            p.innerHTML = formattedText;
86        }
87    }
88
89    if (btnLink) {
90        const a = header.querySelector('a');
91        if (a) a.href = btnLink;
92    }
93
94    if (btnText) {
95        const btn = header.querySelector('.btn-tourism');
96        if (btn) {
97            // Keep the SVG icon
98            const svg = btn.querySelector('svg');
99            btn.innerHTML = '';
100            if (svg) btn.appendChild(svg);
101            btn.appendChild(document.createTextNode(btnText));
102        }
103    }
104
105    if (fields["Acesso rápido"]) {
106        RenderAcessoRapidoHome(fields["Acesso rápido"]);
107    }
108}
109
110let currentLocaisSlide = 0;
111let locaisInterval = null;
112let isLocaisPaused = false;
113
114const RenderLocaisHome = (items) => {
115    const section = document.querySelector('.tourism-section');
116    const gallery = document.querySelector('.tourism-gallery');
117    if (!gallery) return;
118    gallery.innerHTML = '';
119
120    items.forEach((item, index) => {
121        const div = document.createElement('div');
122        div.className = 'gallery-item small locais-slide-item';
123        div.innerHTML = `
124            <img src="${item.imagem || '/eficiente/sites/blumenau/images/tourism-card1.png'}" alt="${item.titulo}">
125            <div class="caption">${item.titulo}</div>
126        `;
127        if (item.link) {
128            div.style.cursor = 'pointer';
129            div.onclick = () => window.location.href = item.link;
130        }
131        gallery.appendChild(div);
132    });
133
134    const carouselContainer = section ? section.querySelector('.tourism-carousel') : null;
135
136    if (items.length > 3) {
137        if (carouselContainer) carouselContainer.style.display = 'flex';
138
139        if (carouselContainer) {
140            const btnPrev = carouselContainer.querySelector('.btn-prev');
141            const btnNext = carouselContainer.querySelector('.btn-next');
142            const btnPause = carouselContainer.querySelector('.btn-pause');
143
144            if (btnPrev) btnPrev.onclick = () => ShowLocaisSlide(currentLocaisSlide - 1);
145            if (btnNext) btnNext.onclick = () => ShowLocaisSlide(currentLocaisSlide + 1);
146            if (btnPause) btnPause.onclick = () => {
147                isLocaisPaused = !isLocaisPaused;
148                btnPause.textContent = isLocaisPaused ? '▶ Continuar' : '❚❚ Pausar';
149                if (isLocaisPaused) clearInterval(locaisInterval);
150                else StartLocaisTimer();
151            };
152        }
153
154        StartLocaisTimer();
155        ShowLocaisSlide(0);
156    } else {
157        if (carouselContainer) carouselContainer.style.display = 'none';
158        const allItems = gallery.querySelectorAll('.locais-slide-item');
159        allItems.forEach(item => item.style.display = 'block');
160    }
161}
162
163const StartLocaisTimer = () => {
164    clearInterval(locaisInterval);
165    locaisInterval = setInterval(() => {
166        if (!isLocaisPaused) ShowLocaisSlide(currentLocaisSlide + 1);
167    }, 8000);
168}
169
170const ShowLocaisSlide = (slideIndex) => {
171    const items = document.querySelectorAll('.tourism-gallery .locais-slide-item');
172    if (items.length === 0) return;
173
174    const totalSlides = Math.ceil(items.length / 3);
175    if (slideIndex >= totalSlides) slideIndex = 0;
176    if (slideIndex < 0) slideIndex = totalSlides - 1;
177
178    const start = slideIndex * 3;
179    const end = start + 3;
180
181    items.forEach((item, i) => {
182        item.style.display = (i >= start && i < end) ? 'block' : 'none';
183        if (item.style.display === 'block') {
184            item.style.opacity = 0;
185            setTimeout(() => item.style.opacity = 1, 10);
186        }
187    });
188
189    currentLocaisSlide = slideIndex;
190}
191
192const RenderAcessoRapidoHome = (items) => {
193    const grid = document.querySelector('.quick-cards-grid');
194    if (!grid || !items || !Array.isArray(items)) return;
195    grid.innerHTML = '';
196
197    items.forEach(item => {
198        const card = document.createElement('a');
199        card.href = item["Link"] || '#';
200        card.className = 'quick-card';
201
202        const bgImg = item["Imagem de fundo"] ? `${item["Imagem de fundo"]}` : '/eficiente/sites/blumenau/images/card-bg1.png';
203        card.style.backgroundImage = `url("${bgImg}")`;
204
205        const iconImg = item["Ícone"] ? `${item["Ícone"]}` : '/eficiente/sites/blumenau/images/icon-megafone.png';
206
207        card.innerHTML = `
208            <span class="icon"><img src="${iconImg}" alt="${item["Título"]}"></span>
209            <span class="label">${item["Título"] || ''}</span>
210            <span class="description">${item["Subtítulo"] || ''}</span>
211            <div class="card-strip"></div>
212            <span class="acess-btn">
213                Acessar
214                <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
215                    <path d="M2.91675 7H11.0834" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
216                    <path d="M7 2.9165L11.0833 6.99984L7 11.0832" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
217                </svg>
218            </span>
219        `;
220        grid.appendChild(card);
221    });
222}
223
224const RenderPublicacoesOficiais = (publicacoes) => {
225    const list = document.querySelector('.pub-list');
226    if (!list) return;
227
228    // Keep the "Mais Publicações" link
229    const viewAllLink = list.querySelector('.view-all');
230
231    // Clear existing list items except the "view-all" one
232    list.querySelectorAll('li:not(.view-all)').forEach(item => item.remove());
233
234    publicacoes.forEach(p => {
235        const li = document.createElement('li');
236        const target = p.target || '_self';
237        li.innerHTML = `<a href="${p.link}" target="${target}">${p.titulo}</a>`;
238        if (viewAllLink) {
239            list.insertBefore(li, viewAllLink);
240        } else {
241            list.appendChild(li);
242        }
243    });
244}
245
246const RenderServices = (services) => {
247    const grid = document.querySelector('.services-grid');
248    if (!grid) return;
249
250    // Keep the "Mais Serviços" card if it exists
251    const maisServicosCard = grid.querySelector('.card-mais');
252
253    // Clear other cards
254    grid.querySelectorAll('.service-card-home:not(.card-mais)').forEach(card => card.remove());
255
256    services.forEach(s => {
257        const card = document.createElement('a');
258        card.href = '/eficiente/sites/blumenau/secao/servicos/' + s.servicoid;
259        card.className = 'service-card-home';
260        card.innerHTML = `
261            <div class="service-card">
262                <div class="card-header-area">
263                    <span class="icon"><img src="${s.temaicone ? s.temaicone : '/eficiente/classes/cartaservicos/icones/outros.svg'}" alt="${s.serviconome}"></span>${s.temanome}
264                </div>
265                <div class="card-body">
266                    <div class="card-title">${s.serviconome}</div>
267                    <div class="card-badges"></div>
268                </div>
269                <a href="/eficiente/sites/blumenau/secao/servicos/${s.servicoid}" class="btn-access">Acessar →</a>
270            </div>
271        `;
272        if (maisServicosCard) {
273            grid.insertBefore(card, maisServicosCard);
274        } else {
275            grid.appendChild(card);
276        }
277    });
278}
279
280let currentNewsSlide = 0;
281let newsInterval = null;
282let isNewsPaused = false;
283let globalNoticias = [];
284
285const RenderNoticias = (noticias) => {
286    const grid = document.querySelector('.news-grid');
287    if (!grid) return;
288    grid.innerHTML = '';
289    globalNoticias = noticias;
290
291    noticias.forEach((n, i) => {
292        const card = document.createElement('a');
293        card.href = n.link;
294        card.className = 'news-card news-slide-item';
295        card.style.display = (i < 3) ? 'block' : 'none';
296        card.innerHTML = `
297            <div class="news-thumb" style="background-image: url('${n.imagem}');">
298                <span class="news-category">${n.categoria || n.secao}</span>
299            </div>
300            <div class="news-body">
301                <span class="news-date">
302                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
303                        <path d="M5.33325 1.33325V3.99992" stroke="#446C8C" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
304                        <path d="M10.6667 1.33325V3.99992" stroke="#446C8C" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
305                        <path d="M12.6667 2.66675H3.33333C2.59695 2.66675 2 3.2637 2 4.00008V13.3334C2 14.0698 2.59695 14.6667 3.33333 14.6667H12.6667C13.403 14.6667 14 14.0698 14 13.3334V4.00008C14 3.2637 13.403 2.66675 12.6667 2.66675Z" stroke="#446C8C" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
306                        <path d="M2 6.66675H14" stroke="#446C8C" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
307                    </svg>
308                    ${n.data}</span>
309                <h3>${n.titulo}</h3>
310                <div class="read-more">Acessar notícia
311                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
312                        <path d="M3.33325 8H12.6666" stroke="#016CB0" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
313                        <path d="M8 3.33325L12.6667 7.99992L8 12.6666" stroke="#016CB0" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
314                    </svg>
315                </div>
316            </div>
317        `;
318        grid.appendChild(card);
319    });
320
321    const container = document.querySelector('.news-section');
322    const btnPrev = container.querySelector('.btn-prev');
323    const btnNext = container.querySelector('.btn-next');
324    const btnPause = container.querySelector('.btn-pause');
325
326    if (btnPrev) btnPrev.onclick = () => ShowNewsSlide(currentNewsSlide - 1);
327    if (btnNext) btnNext.onclick = () => ShowNewsSlide(currentNewsSlide + 1);
328    if (btnPause) btnPause.onclick = () => {
329        isNewsPaused = !isNewsPaused;
330        btnPause.textContent = isNewsPaused ? '▶ Continuar' : '❚❚ Pausar';
331        if (isNewsPaused) clearInterval(newsInterval);
332        else StartNewsTimer();
333    };
334
335    StartNewsTimer();
336}
337
338const StartNewsTimer = () => {
339    clearInterval(newsInterval);
340    newsInterval = setInterval(() => {
341        if (!isNewsPaused) ShowNewsSlide(currentNewsSlide + 1);
342    }, 8000);
343}
344
345const ShowNewsSlide = (slideIndex) => {
346    const items = document.querySelectorAll('.news-grid .news-slide-item');
347    if (items.length === 0) return;
348
349    const totalSlides = Math.ceil(items.length / 3);
350    if (slideIndex >= totalSlides) slideIndex = 0;
351    if (slideIndex < 0) slideIndex = totalSlides - 1;
352
353    const start = slideIndex * 3;
354    const end = start + 3;
355
356    items.forEach((item, i) => {
357        item.style.display = (i >= start && i < end) ? 'block' : 'none';
358        // Simple fade effect
359        if (item.style.display === 'block') {
360            item.style.opacity = 0;
361            setTimeout(() => item.style.opacity = 1, 10);
362        }
363    });
364
365    currentNewsSlide = slideIndex;
366}
367
368let currentBannerIndex = 0;
369let bannerInterval = null;
370let isPaused = false;
371
372const RenderBannersHome = (banners) => {
373    const container = document.querySelector('.home-banner-section');
374    if (!container) return;
375
376    // Remove existing banners
377    container.querySelectorAll('.full-banner').forEach(b => b.remove());
378
379    const carouselContainer = container.querySelector('.carousel-container');
380    const isMobile = window.innerWidth <= 768;
381
382    banners.forEach((b, i) => {
383        const div = document.createElement('a');
384        div.className = 'full-banner' + (i === 0 ? ' active' : '');
385        div.href = b.link || '#';
386        const imgUrl = (isMobile && b.imagemMobile && b.imagemMobile.trim() !== '')
387            ? b.imagemMobile
388            : (b.imagem || '/eficiente/sites/blumenau/images/banner-1.png');
389        div.style.backgroundImage = `url('${imgUrl}')`;
390        container.insertBefore(div, carouselContainer);
391    });
392
393    const btnPrev = container.querySelector('.btn-prev');
394    const btnNext = container.querySelector('.btn-next');
395    const btnPause = container.querySelector('.btn-pause');
396
397    if (btnPrev) btnPrev.onclick = () => ShowBanner(currentBannerIndex - 1);
398    if (btnNext) btnNext.onclick = () => ShowBanner(currentBannerIndex + 1);
399    if (btnPause) btnPause.onclick = () => {
400        isPaused = !isPaused;
401        btnPause.textContent = isPaused ? '▶ Continuar' : '❚❚ Pausar';
402        if (isPaused) clearInterval(bannerInterval);
403        else StartBannerTimer();
404    };
405
406    StartBannerTimer();
407}
408
409const StartBannerTimer = () => {
410    clearInterval(bannerInterval);
411    bannerInterval = setInterval(() => {
412        if (!isPaused) ShowBanner(currentBannerIndex + 1);
413    }, 5000);
414}
415
416const ShowBanner = (index) => {
417    const banners = document.querySelectorAll('.home-banner-section .full-banner');
418    if (banners.length === 0) return;
419
420    if (index >= banners.length) index = 0;
421    if (index < 0) index = banners.length - 1;
422
423    banners.forEach((b, i) => {
424        b.classList.toggle('active', i === index);
425    });
426
427    currentBannerIndex = index;
428}
429
430let currentComunicadoIndex = 0;
431let comunicadoInterval = null;
432let isComunicadoPaused = false;
433
434const RenderComunicadosHome = (comunicados) => {
435    const container = document.querySelector('.comm-column');
436    if (!container) return;
437
438    // Remove existing banners
439    container.querySelectorAll('.comm-banner').forEach(b => b.remove());
440
441    const carouselContainer = container.querySelector('.carousel-container');
442
443    comunicados.forEach((c, i) => {
444        const div = document.createElement('a');
445        div.className = 'comm-banner' + (i === 0 ? ' active' : '');
446        div.href = c.link;
447        div.style.display = 'block';
448        div.innerHTML = `<img src="${c.imagem || "data:image/svg+xml,<svg width='641' height='430' viewBox='0 0 641 430' xmlns='http://www.w3.org/2000/svg'><rect width='641' height='430' fill='%23d0d0d0'/></svg>"}" alt="${c.titulo}">`;
449        container.insertBefore(div, carouselContainer);
450    });
451
452    const btnPrev = container.querySelector('.btn-prev');
453    const btnNext = container.querySelector('.btn-next');
454    const btnPause = container.querySelector('.btn-pause');
455
456    if (btnPrev) btnPrev.onclick = () => ShowComunicado(currentComunicadoIndex - 1);
457    if (btnNext) btnNext.onclick = () => ShowComunicado(currentComunicadoIndex + 1);
458    if (btnPause) btnPause.onclick = () => {
459        isComunicadoPaused = !isComunicadoPaused;
460        btnPause.textContent = isComunicadoPaused ? '▶ Continuar' : '❚❚ Pausar';
461        if (isComunicadoPaused) clearInterval(comunicadoInterval);
462        else StartComunicadoTimer();
463    };
464
465    StartComunicadoTimer();
466}
467
468const StartComunicadoTimer = () => {
469    clearInterval(comunicadoInterval);
470    comunicadoInterval = setInterval(() => {
471        if (!isComunicadoPaused) ShowComunicado(currentComunicadoIndex + 1);
472    }, 6000); // Slightly different timing for variation
473}
474
475const ShowComunicado = (index) => {
476    const banners = document.querySelectorAll('.comm-column .comm-banner');
477    if (banners.length === 0) return;
478
479    if (index >= banners.length) index = 0;
480    if (index < 0) index = banners.length - 1;
481
482    banners.forEach((b, i) => {
483        b.classList.toggle('active', i === index);
484    });
485
486    currentComunicadoIndex = index;
487}
488
489const RenderBannerSecundarioHome = (banners) => {
490    const container = document.querySelector('#banner-secundario');
491    if (!container) return;
492
493    // Remove existing content
494    container.innerHTML = '<!-- Dynamic Content -->';
495
496    if (banners && banners.length > 0) {
497        const b = banners[0]; // Just use the first one
498        const img = document.createElement('img');
499        const isMobile = window.innerWidth <= 768;
500        const imgUrl = (isMobile && b.imagemMobile && b.imagemMobile.trim() !== '')
501            ? b.imagemMobile
502            : (b.imagem || '/eficiente/sites/blumenau/images/banner-2.png');
503        img.src = imgUrl;
504        img.alt = b.titulo;
505        img.className = 'active'; // Just keep it active/visible
506        if (b.link) {
507            img.style.cursor = 'pointer';
508            img.onclick = () => window.location.href = b.link;
509        }
510        container.appendChild(img);
511    }
512}
513
514window.addEventListener('load', function () {
515    const tabs = document.querySelector('#home-tabs');
516    if (tabs) {
517        GetServicoTemas().then(data => {
518            if (data && data.length > 0) {
519                tabs.innerHTML = '';
520                data.forEach((t, index) => {
521                    const tab = document.createElement('button');
522                    tab.textContent = t.publiconome;
523                    if (index === 0) {
524                        tab.classList.add('active');
525                        document.querySelector('.home-btn-more-services').href = `/eficiente/sites/blumenau/secao/servicos?perfis=${t.publicoid}`;
526                        RenderServices(t.servicos);
527                    }
528                    tab.addEventListener('click', (e) => {
529                        document.querySelectorAll('#home-tabs button').forEach(b => b.classList.remove('active'));
530                        e.target.classList.add('active');
531                        document.querySelector('.home-btn-more-services').href = `/eficiente/sites/blumenau/secao/servicos?perfis=${t.publicoid}`;
532                        RenderServices(t.servicos);
533                    });
534                    tabs.appendChild(tab);
535                });
536            }
537        });
538    }
539
540    const subjectsGrid = document.querySelector('.subjects-grid');
541    if (subjectsGrid) {
542        GetServicoAssuntos().then(data => {
543            if (data && data.length > 0) {
544                subjectsGrid.innerHTML = '';
545                data.forEach(s => {
546                    if (s.id == 26) { return; }
547                    const card = document.createElement('a');
548                    card.href = '/eficiente/sites/blumenau/secao/servicos?temas=' + s.id;
549                    card.className = 'subject-card';
550                    card.innerHTML = `
551                        <div class="subject-icon blue">
551<img src="${s.icone ? s.icone : '/eficiente/classes/cartaservicos/icones/outros.svg'}" alt="${s.temanome}"></div>
552                        <span>${s.nome}</span>
553                    `;
554                    subjectsGrid.appendChild(card);
555                });
556            }
557        });
558    }
559
560    GetNoticiasHome().then(data => {
561        if (data && data.length > 0) {
562            RenderNoticias(data);
563        }
564    });
565
566    GetBannersHome().then(data => {
567        if (data && data.length > 0) {
568            RenderBannersHome(data);
569        }
570    });
571
572    GetComunicadosHome().then(data => {
573        if (data && data.length > 0) {
574            RenderComunicadosHome(data);
575        }
576    });
577
578    // Removido o carregamento via publicações, agora é via secao.home.php (home.xml)
579    /*
580    GetAcessoRapidoHome().then(data => {
581        if (data && data.length > 0) {
582            RenderAcessoRapidoHome(data);
583        }
584    });
585    */
586
587    GetLocaisHome().then(data => {
588        if (data && data.length > 0) {
589            RenderLocaisHome(data);
590        }
591    });
592
593    GetSecaoHome().then(data => {
594        if (data) {
595            RenderSecaoHome(data);
596        }
597    });
598
599    GetBannerSecundarioHome().then(data => {
600        if (data && data.length > 0) {
601            RenderBannerSecundarioHome(data);
602        }
603    });
604
605    GetPublicacoesOficiais().then(data => {
606        if (data && data.length > 0) {
607            RenderPublicacoesOficiais(data);
608        }
609    });
610});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.