PageSourceSearch

https://www.aigae.org/area_riservata/lib/js/script.js?v=1790857500

js aigae.org collected 2026-10-01 12:26:09 UTC 38,139 bytes, 996 lines download raw bytes

1// Variabili globali per parametri URL
2var idcorso, idescursione, biennio, idsocio, azione, keycorso, codiceEsito, esito, codTrans, descrizione;
3
4jQuery(document).ready(function () {
5	const switchEl = document.getElementById('themeSwitch');
6	const body = document.body;
7
8	// Imposta il tema iniziale da localStorage o database
9	const savedTheme = localStorage.getItem('theme');
10	if( savedTheme )
11	{
12		if( switchEl )
13		{
14			body.setAttribute('data-bs-theme', savedTheme);
15			switchEl.checked = savedTheme === 'dark';
16		}
17	}
18	else
19	{
20		// Carica il tema dal database se non presente in localStorage
21		$.ajax({
22			url: '/area_riservata/lib/api/api_interne.php?tipo_api=get_tema_utente',
23			type: 'POST',
24			success: function(response) {
25				if (response.success && response.tema) {
26					body.setAttribute('data-bs-theme', response.tema);
27					if( switchEl ) switchEl.checked = response.tema === 'dark';
28					localStorage.setItem('theme', response.tema);
29				} else {
30					// Default a light se non trovato
31					body.setAttribute('data-bs-theme', 'light');
32					if( switchEl ) switchEl.checked = false;
33					localStorage.setItem('theme', 'light');
34				}
35			},
36			error: function(xhr, status, error) {
37				console.error('Errore caricamento tema:', error);
38				// Default a light in caso di errore
39				body.setAttribute('data-bs-theme', 'light');
40				if( switchEl ) switchEl.checked = false;
41				localStorage.setItem('theme', 'light');
42			}
43		});
44	}
45
46	if( switchEl )
47	{
48		// Al cambio dello switch
49		switchEl.addEventListener('change', () => {
50			const theme = switchEl.checked ? 'dark' : 'light';
51			body.setAttribute('data-bs-theme', theme);
52			localStorage.setItem('theme', theme);
53			
54			// Salva il tema nel database
55			$.ajax({
56				url: '/area_riservata/lib/api/api_interne.php?tipo_api=salva_tema',
57				type: 'POST',
58				data: { tema: theme },
59				success: function(response) {
60					if (!response.success) {
61						console.error('Errore salvataggio tema:', response.message);
62					}
63				},
64				error: function(xhr, status, error) {
65					console.error('Errore AJAX salvataggio tema:', error);
66				}
67			});
68		});
69	}
70
71	// Aggiungi onerror a tutte le immagini
72	$('img').attr('onerror', "this.src='img/loghi/Aigae_logo_n.png'");
73
74});
75
76function checkFileSize(input) {
77	// console.log("Controllo dimensione file...", input);
78	var maxSize = parseInt(jQuery(input).data('max-size'));
79	// console.log("Dimensione massima consentita:", maxSize);
80	var file = input.files[0];
81	if (file && file.size > maxSize) {
82		alert('Il file selezionato è troppo grande. La dimensione massima consentita è ' + (maxSize / 1000000) + ' MB.');
83		input.value = '';
84		return false;
85	}
86	return true;
87}
88
89function rinnovaOra() {
90    cambia_pag('socio', 'rinnovo');
91}
92
93/**
94 * Restituisce le impostazioni base per DataTable in italiano, con Bootstrap, esportazione e responsive.
95 * @param {Object} options - Opzioni specifiche (colonne, ajax, ecc.)
96 * @returns {Object} Configurazione DataTable
97 */
98function getBaseDataTableConfig(options = {}) {
99	const filename = options.filename;
100	const baseConfig = {
101		language: {
102			url: 'lib/js/i18n/it-IT.json'
103		},
104		dom: 'Blfrtip',
105		buttons: filename ? [
106			{ extend: 'excel', filename: filename },
107			{ extend: 'pdf', filename: filename }
108		] : ['excel', 'pdf'],
109		responsive: true,
110		lengthMenu: [10, 25, 50, 100, -1],
111		pageLength: 25,
112		initComplete: function () {
113			$(this.api().table().container()).find('img').attr('onerror', "this.src='img/loghi/Aigae_logo_n.png'");
114		},
115		drawCallback: function () {
116			$(this.api().table().container()).find('img').attr('onerror', "this.src='img/loghi/Aigae_logo_n.png'");
117		},
118	};
119	// Rimuovi filename dalle options per evitare conflitti
120	delete options.filename;
121	return Object.assign(baseConfig, options);
122}
123function populateAnniCorsi() {
124	$.ajax({
125		url: 'lib/api/api_interne.php?tipo_api=get_anni_corsi',
126		type: 'POST',
127		dataType: 'json',
128		success: function (result) {
129			console.log(result);
130			if (result.success && result.data) {
131				var select = $('.select_anno');
132				select.empty();
133				select.append('<option value="">---</option>');
134				var annoCorrente = new Date().getFullYear();
135				result.data.forEach(function (anno) {
136					var selected = (anno == annoCorrente) ? 'selected' : '';
137					select.append('<option value="' + anno + '" ' + selected + '>
137' + anno + '</option>');
138				});
139			}
140		}
141	});
142}
143
144function login() {
145	var username = jQuery('#username').val();
146	var password = jQuery('#password').val();
147
148	jQuery.ajax({
149		url: site_host + '/area_riservata/lib/api/api_interne.php?tipo_api=login',
150		type: 'POST',
151		data: { username: username, password: password },
152		dataType: 'json',
153		success: function (result) {
154			if( result.success )
155			{
156				var pagina = '';
157				var tipouser = result.tipouser;
158				if( tipouser == "socio" )
159				{
160					if( result.azione == "login_pagamento" )
161					{
162						const oggi = Date.now();
163
164						const currAnno = new Date().getFullYear();
165						const nextAnno = currAnno + 1;
166
167						// Attenzione: Date in JS usa millisecondi
168						const startDate = new Date(currAnno+'-12-31').getTime();
169						const endDate = new Date(nextAnno+getRinnovoDate()).getTime();
170
171						if( oggi > startDate && oggi <= endDate )
172						{
173							const strEndDate = new Intl.DateTimeFormat('it-IT', {
174								day: '2-digit',
175								month: '2-digit',
176								year: 'numeric',
177								hour: '2-digit',
178								minute: '2-digit',
179								hour12: false
180							}).format(endDate);
181
182							showBootstrapAlert('Sarà possibile rinnovare la tua tessera dal ' + strEndDate, 'danger');
183							return;
184						}
185						else
186						{
187							pagina = '/area_riservata/pages/base.php?pagina=socio';
188						}
189					}
190					else if( result.azione == "login" )
191					{
192						pagina = '/area_riservata/pages/';
193					}
194				}
195				else
196				{
197					pagina = "/gestione_soci/auto-login.php?uid=" + result.iduser + "&exp=" + result.expiry + "&sig=" + result.token + "&username=" + result.username + "&tipouser=" + result.tipouser;	
198				}
199
200				var redirectUrl = site_host + pagina;
201				if( tipouser == "socio" && result.mostra_popup_crediti_biennio_precedente )
202				{
203					showCreditiBiennioPrecedentePopup(function(){
204						window.location.replace(redirectUrl);
205					});
206				}
207				else
208				{
209					window.location.replace(redirectUrl);
210				}
211			}
212			else
213			{
214				if( result.azione == "reiscrizione_no_login" )
215					showBootstrapConfirm('Attenzione, la tua tessera è scaduta da più di un anno!<br />Per poter accedere devi effettuare la reiscrizione <a href=\'/subscription\' style=\'cursor:pointer;\'> (Clicca qui)</a> oppure contatta la segreteria.', function(){ window.location.href = '/subscription' });
216				else if( result.azione == "dimesso" )
217					showBootstrapAlert('Attenzione, socio dimesso. Contatta la segreteria per maggiori informazioni.', 'danger');
218				else if( result.azione == "bloccato" )
219					showBootstrapAlert('Attenzione, il tuo account e\' stato bloccato fino al ' + result.bloccato_data + ', contatta la segreteria per maggiori informazioni.', 'danger');
220				else if( result.azione == "pwd_scaduta" )
221					showBootstrapConfirm('Attenzione, la tua password è scaduta. Prosegui per cambiarla.', function(){ requestPasswordChange(result.iduser); });
222				else
223					showBootstrapAlert('Credenziali errate', 'danger');
224			}
225		},
226		error: function (xhr, status, error) {
227			console.log('Errore AJAX:', status, error);
228			showBootstrapAlert('Errore connessione durante il login.', 'danger');
229		}
230	});
231}
232
233function showBootstrapAlert(message, type = 'success') {
234	jQuery('#bootstrapAlertModal').remove(); // Rimuovi modale esistente se presente
235	// Crea modale Bootstrap
236	var modal = document.createElement('div');
237	modal.id = 'bootstrapAlertModal';
238	modal.className = 'modal fade';
239	modal.tabIndex = -1;
240	modal.innerHTML = `
241	<div class="modal-dialog">
242		<div class="modal-content">
243			<div class="modal-header bg-${type}">
244				<h5 class="modal-title white-text">${type === 'danger' ? 'Errore' : 'Avviso'}</h5>
245				<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
246			</div>
247			<div class="modal-body">
248				<p id="bootstrapAlertMessage"></p>
249			</div>
250		</div>
251	</div>`;
252	document.body.appendChild(modal);
253
254	document.getElementById('bootstrapAlertMessage').innerText = message;
255	const bsModal = new bootstrap.Modal(modal, { backdrop: 'static' });
256	bsModal.show();
257	setTimeout(function () {
258		bsModal.hide();
259	}, 3000);
260}
261
262function showBootstrapConfirm(message, callback) {
263	// Crea modale Bootstrap se non esiste
264	let modal = document.getElementById('bootstrapConfirmModal');
265	if (!modal) {
266		modal = document.createElement('div');
267		modal.id = 'bootstrapConfirmModal';
268		modal.className = 'modal fade';
269		modal.tabIndex = -1;
270		modal.innerHTML = `
271		<div class="modal-dialog">
272			<div class="modal-content">
273				<div class="modal-header">
274					<h5 class="modal-title">Conferma</h5>
275					<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
276				</div>
277				<div class="modal-body">
278					<p id="bootstrapConfirmMessage"></p>
279				</div>
280				<div class="modal-footer">
281					<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annulla</button>
282					<button type="button" class="btn btn-primary" id="bootstrapConfirmOk">Conferma</button>
283				</div>
284			</div>
285		</div>`;
286		document.body.appendChild(modal);
287	}
288	document.getElementById('bootstrapConfirmMessage').innerHTML = message;
289	const okBtn = document.getElementById('bootstrapConfirmOk');
290	// Rimuovi eventuali listener precedenti
291	okBtn.onclick = function () {
292		const modalInstance = bootstrap.Modal.getInstance(modal);
293		modalInstance.hide();
294		callback(true);
295	};
296	const bsModal = new bootstrap.Modal(modal, { backdrop: 'static' });
297	bsModal.show();
298}
299
300function showCreditiBiennioPrecedentePopup(callback) {
301	jQuery('#creditiBiennioPrecedenteModal').remove();
302
303	var modal = document.createElement('div');
304	modal.id = 'creditiBiennioPrecedenteModal';
305	modal.className = 'modal fade';
306	modal.tabIndex = -1;
307	modal.setAttribute('aria-labelledby', 'creditiBiennioPrecedenteModalLabel');
308	modal.setAttribute('aria-hidden', 'true');
309	modal.innerHTML = `
310	<div class="modal-dialog modal-lg modal-dialog-scrollable">
311		<div class="modal-content">
312			<div class="modal-header">
313				<h5 class="modal-title" id="creditiBiennioPrecedenteModalLabel">Aggiornamento e formazione continua</h5>
314				<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Chiudi"></button>
315			</div>
316			<div class="modal-body">
317				<p><strong>Ai soci Aigae non in regola con l'aggiornamento e la formazione continua.</strong></p>
318				<p>Cari colleghi,<br>
319				come sapete Aigae è associazione riconosciuta dal MISE, che indica gli standard di qualità per esercitare la professione di Guida Ambientale Escursionistica.</p>
320				<p>In applicazione delle Direttive UE e della L. 4/2013, infatti, tutte le GAE iscritte al registro nazionale hanno obbligo di aggiornamento e formazione continua.</p>
321				<p>Noi riteniamo questo obbligo una grande opportunità di migliorare sempre più il nostro lavoro a contatto con il pubblico e per l'ambiente del nostro amato e complesso Paese.</p>
322				<p>Nella tua area riservata, potrai controllare i crediti acquisiti e nel caso segnalare a <a href="mailto:[email protected]">[email protected]</a> eventuali errori. Se mancano corsi da te effettuati, potrai fare domanda di accredito direttamente con la nuova procedura digitale cui potrai accedere da "i miei crediti" nella tua area riservata.</p>
323				<p>Con la presente, allo stato attuale delle nostre conoscenze sul tuo aggiornamento professionale, questo messaggio purtroppo è un <strong>RICHIAMO FORMALE</strong> secondo l’art. 146 comma a) del Regolamento Nazionale per il socio poiché non è stato rispettato l'obbligo di aggiornamento e formazione professionale continua.</p>
324				<p>Ti chiediamo uno straordinario impegno per mettere in regola la tua situazione entro e non oltre il <strong>30 giugno 2026</strong>, in difetto di adempimento sarà il Collegio dei Probiviri di Aigae ad assumere le decisioni competenti, compresa la sospensione o radiazione dall'Associazione.</p>
325				<p>Ci auguriamo di cuore che tu voglia comprendere e risolvere questa particolare situazione che si è venuta a creare.</p>
326				<p>Aigae è un'Associazione di categoria, la più grande nel settore in Italia, quindi non può essere solo lo strumento per avere un'assicurazione.</p>
327				<p>Resta in contatto, controlla i tuoi dati personali in area riservata, controlla se ricevi la newsletter, partecipa alla vita associativa, formati ed aggiornati, per rafforzare sempre più AIGAE, quale strumento di partecipazione e di rafforzamento della nostra categoria professionale in Italia.</p>
328				<p>Buoni passi.</p>
329				<p>Daniela D'Amico<br>
330				Presidente Commissione Tecnico-Scientifica e Formazione di Aigae.</p>
331			</div>
332			<div class="modal-footer">
333				<button type="button" class="btn btn-primary" id="creditiBiennioPrecedenteOk">Ho letto</button>
334			</div>
335		</div>
336	</div>`;
337	document.body.appendChild(modal);
338
339	var redirected = false;
340	var goNext = function () {
341		if( redirected )
342			return;
343
344		redirected = true;
345		if( typeof callback === 'function' )
346			callback();
347	};
348
349	var bsModal = new bootstrap.Modal(modal, { backdrop: 'static' });
350	document.getElementById('creditiBiennioPrecedenteOk').onclick = function () {
351		bsModal.hide();
352		goNext();
353	};
354	modal.addEventListener('hidden.bs.modal', goNext, { once: true });
355	bsModal.show();
356}
357
358function get_menu_tipo(tipo_menu) {
359	jQuery.ajax({
360		url: site_host + '/lib/api/api_interne.php?tipo_api=get_menu_tipo',
361		type: 'POST',
362		dataType: 'json',
363		data: { tipo_menu: tipo_menu },
364		success: function (data) {
365			console.log(data)
366		},
367		error: function (xhr, status, error) {
368			console.error('Errore AJAX:', status, error);
369			showBootstrapAlert('Errore nel caricamento del menu.', 'danger');
370		}
371	});
372}
373
374function cambia_pag(pagina, id_pagina = '', reset = '') {
375	
376	//gestione evidenziazione menu
377	console.log('Cambia pagina in: ' + pagina + ' ' + id_pagina);
378	jQuery('.btn-toggle').removeClass('active');
379	var navButton = jQuery('#' + pagina.replace('/', '-') + id_pagina.replace('/', '-') + '-nav');
380	if (navButton.length) {
381		navButton.addClass('active');
382	}else{
383		var navButton = jQuery('.' + pagina.replace('/', '-') + '-nav');
384		if (navButton.length) {
385			navButton.addClass('active');
386		}
387	}
388
389	// Apri il menu padre se non è già aperto
390	if (navButton.length) {
391		navButton.each(function() {
392			var collapse = jQuery(this).closest('.collapse');
393			if (collapse.length && !collapse.hasClass('show')) {
394				collapse.collapse('show');
395			}
396		});
397	}
398
399	window.currentPage = pagina; // Imposta la pagina corrente
400
401	jQuery('#contenuto_pagina').empty();
402	var link_pag = pagina + ".php";
403	if (pagina == 'socio') {
404		var urlParams = new URLSearchParams(window.location.search);
405		var params = [];
406		for (let [key, value] of urlParams) {
407			params.push(key + '=' + value);
408		}
409		if (id_pagina == 'skip' && !urlParams.has('skip_photo')) {
410			params.push('skip_photo=1');
411		}
412		if (id_pagina == 'rinnovo') {
413			params.push('rinnovo=1');
414		}
415		if (params.length > 0) {
416			link_pag += '?' + params.join('&');
417		}
418	}
419	else if (pagina == 'cms') {
420		link_pag += '?idpag=' + id_pagina;
421		pagina = 'cms/' + id_pagina;
422	}
423	else if (pagina === 'crediti' && biennio && reset !== 'reset') {
424		link_pag += biennio ? '?biennio=' + biennio : '';
425		link_pag += idsocio ? '&idsocio=' + idsocio : '';
426	}
427	else if (pagina === 'gest_corsi_direttore' && azione && reset !== 'reset') {
428		link_pag += azione ? '?azione=' + azione : '';
429		link_pag += idcorso ? '&idcorso=' + idcorso : '';
430	}
431	else if (pagina === 'pagamento_corso' && keycorso && reset !== 'reset') {
432		link_pag += keycorso ? '?keycorso=' + keycorso : '';
433		link_pag += idcorso ? '&idcorso=' + idcorso : '';
434	}
435	else if (pagina === 'escursione' && idescursione && reset !== 'reset') {
436		link_pag += idescursione ? '?idescursione=' + idescursione : '';
437	}
438	else if ((pagina === 'pagamento' || pagina === 'card' || pagina === 'prodotti') && codiceEsito && reset !== 'reset') {
439		link_pag += codiceEsito ? '?codiceEsito=' + codiceEsito : '';
440		link_pag += esito ? '&esito=' + esito : '';
441		link_pag += codTrans ? '&codTrans=' + codTrans : '';
442		link_pag += descrizione ? '&descrizione=' + descrizione : '';
443	}
444	else if ((pagina === 'invio_mail_corsi' || pagina === 'richiedi_crediti_partecipanti' ) && reset !== 'reset') {
445		link_pag += idcorso ? '?idcorso=' + idcorso : '';
446	}
447	else if (pagina === 'escursioni_socio_cammina_natura') {
448		var link_pag = "escursioni_socio.php?azione=cammina";
449	}
450	else if (pagina === 'nuova_escursione_cammina_natura') {
451		var link_pag = "nuova_escursione.php?azione=cammina";
452	}
453
454
455	// Ottieni i parametri attuali se la pagina è la stessa
456	var currentPath = window.location.pathname;
457	var newPath = "/area_riservata/pages/" + pagina;
458	var isPopState = reset === 'popstate';
459
460	// Se la nuova pagina è una sottopagina della pagina attuale, mantieni i parametri (se reset è vuoto)
461	var finalUrl = isPopState ? currentPath : ((reset === '' && currentPath.startsWith(newPath)) ? currentPath : newPath);
462	if (!isPopState) {
463		history.pushState({ page: pagina }, "", finalUrl);
464	}
465
466	jQuery.get(site_host + '/area_riservata/pages/' + link_pag, function (html_scheda) {
467		jQuery('#contenuto_pagina').append(html_scheda);
468		if (pagina == 'homepage') {
469			showPWAPopup();
470		}
471	});
472
473}
474
475function cambiaTema() {
476	var tema = jQuery('#theme_selector').val();
477	jQuery("body").attr("data-bs-theme", tema);
478}
479
480/**
481 * Visualizza un file (cifrato o meno) nel browser tramite API.
482 * @param {string} filePath - Percorso relativo del file (es: lib/archivio/soci/6463/documento.pdf.enc)
483 * @param {string} tipo - Tipo di accesso (socio, admin, corso, etc.)
484 * @param {boolean} download - Se true, forza il download invece della visualizzazione (default: false)
485 */
486function downloadFile(filePath, tipo = 'socio', download = false) {
487	// Crea un form nascosto per il POST
488	const form = document.createElement('form');
489	form.method = 'POST';
490	form.action = site_host + '/area_riservata/lib/api/api_interne.php?tipo_api=download_file';
491	form.target = '_blank'; // Apri in una nuova scheda/finestra
492
493	// Aggiungi i campi nascosti
494	const filePathInput = document.createElement('input');
495	filePathInput.type = 'hidden';
496	filePathInput.name = 'file_path';
497	filePathInput.value = filePath;
498	form.appendChild(filePathInput);
499
500	const tipoInput = document.createElement('input');
501	tipoInput.type = 'hidden';
502	tipoInput.name = 'tipo';
503	tipoInput.value = tipo;
504	form.appendChild(tipoInput);
505
506	const downloadInput = document.createElement('input');
507	downloadInput.type = 'hidden';
508	downloadInput.name = 'download';
509	downloadInput.value = download ? '1' : '0';
510	form.appendChild(downloadInput);
511
512	// Aggiungi il form al body, invia e rimuovi
513	document.body.appendChild(form);
514	form.submit();
515	document.body.removeChild(form);
516}
517
518/**
519 * Richiede il reset della password
520 */
521function requestPasswordReset() {
522	var identifier = $('#reset_identifier').val().trim();
523	if (!identifier) {
524		showAlert('resetAlert', 'Inserisci numero tessera o email', 'danger');
525		return;
526	}
527
528	$.ajax({
529		url: 'lib/api/api_interne.php?tipo_api=request_password_reset',
530		type: 'POST',
531		data: { identifier: identifier },
532		dataType: 'json',
533		success: function (result) {
534			if (result.success) {
535				showAlert('resetAlert', result.message, 'success');
536				setTimeout(function () {
537					$('#modalResetPassword').modal('hide');
538					$('#formResetPassword')[0].reset();
539				}, 2000);
540			} else {
541				showAlert('resetAlert', result.message, 'danger');
542			}
543		},
544		error: function () {
545			showAlert('resetAlert', 'Errore di connessione', 'danger');
546		}
547	});
548}
549
550/**
551 * Richiede il reset della password
552 */
553function requestPasswordChange(user_id)
554{
555	$.ajax({
556		url: 'lib/api/api_interne.php?tipo_api=request_password_change',
557		type: 'POST',
558		data: { user_id: user_id },
559		dataType: 'json',
560		success: function (result) {
561			if( result.success )
562			{
563				if( result.success )
564					window.location.href = '/area_riservata/reset_password.php?token=' + result.token;
565				else
566					showAlert('resetAlert', result.message, 'danger');
567			}
568			else
569			{
570				showAlert('resetAlert', result.message, 'danger');
571			}
572		},
573		error: function () {
574			showAlert('resetAlert', 'Errore di connessione', 'danger');
575		}
576	});
577}
578
579/**
580 * Resetta la password con il token
581 */
582function resetPassword() {
583	var token = $('#token').val();
584	var newPassword = $('#new_password').val();
585	var confirmPassword = $('#confirm_password').val();
586
587	var passRegex = /^(?=.*\d)(?=.*[\W_])(?=.*[a-z])(?=.*[A-Z])[a-zA-Z\d\W_]{8,}$/;
588
589	if (!newPassword || !newPassword.match(passRegex)) {
590		if (newPassword.length < 8)
591			showAlert('resetAlert', "La password deve essere di almeno 8 caratteri!", 'danger');
592		else if (!newPassword.match(/^(?=.*[A-Z]).*$/))
593			showAlert('resetAlert', 'La password deve contenere almeno un carattere maiuscolo!', 'danger');
594		else if (!newPassword.match(/^(?=.*[a-z]).*$/))
595			showAlert('resetAlert', 'La password deve contenere almeno un carattere minuscolo!', 'danger');
596		else if (!newPassword.match(/^(?=.*\d).*$/))
597			showAlert('resetAlert', 'La password deve contenere almeno un numero', 'danger');
598		else if (!newPassword.match(/^(?=.*[\W_])$/))
599			showAlert('resetAlert', 'La password deve contenere almeno un carattere speciale', 'danger');
600
601		return;
602	}
603
604	if (newPassword !== confirmPassword) {
605		showAlert('resetAlert', 'Le password non coincidono', 'danger');
606		return;
607	}
608
609	$.ajax({
610		url: 'lib/api/api_interne.php?tipo_api=reset_password',
611		type: 'POST',
612		data: { token: token, password: newPassword },
613		dataType: 'json',
614		success: function (result) {
615			if (result.success) {
616				showAlert('resetAlert', result.message + '. Reindirizzamento al login...', 'success');
617				setTimeout(function () {
618					window.location.href = 'index.php';
619				}, 2000);
620			} else {
621				showAlert('resetAlert', result.message, 'danger');
622			}
623		},
624		error: function () {
625			showAlert('resetAlert', 'Errore di connessione', 'danger');
626		}
627	});
628}
629
630
631/**
632 * cambio la password
633 */
634function changePassword() {
635	var username = $('#username').val();
636	var user_id = $('#user_id').val();
637	var current_password = $('#current_password').val();
638	var newPassword = $('#new_password').val();
639	var confirmPassword = $('#confirm_password').val();
640
641	if (!newPassword || newPassword.length < 6) {
642		showAlert('resetAlert', 'La password deve essere di almeno 6 caratteri', 'danger');
643		return;
644	}
645
646	if (newPassword !== confirmPassword) {
647		showAlert('resetAlert', 'Le password non coincidono', 'danger');
648		return;
649	}
650
651	$.ajax({
652		url: 'lib/api/api_interne.php?tipo_api=check_current_password',
653		type: 'POST',
654		data: { username: username, password: current_password },
655		dataType: 'json',
656		success: function (result) {
657			if (result.success) {
658				if (confirm('Sei sicuro di voler cambiare la tua password?')) {
659					$.ajax({
660						url: 'lib/api/api_interne.php?tipo_api=change_password',
661						type: 'POST',
662						data: { user_id: user_id, password: newPassword },
663						dataType: 'json',
664						success: function (result_2) {
665							if (result_2.success) {
666								showAlert('resetAlert', result.message + '. Reindirizzamento al login...', 'success');
667								setTimeout(function () {
668									window.location.href = 'index.php';
669								}, 2000);
670							} else {
671								showAlert('resetAlert', result.message, 'danger');
672							}
673						},
674						error: function () {
675							showAlert('resetAlert', 'Errore di connessione', 'danger');
676						}
677					});
678				}
679
680			} else {
681				showAlert('resetAlert', result.message, 'danger');
682			}
683		},
684		error: function () {
685			showAlert('resetAlert', 'Errore di connessione', 'danger');
686		}
687	});
688}
689
690/**
691 * Mostra un alert in un elemento specifico
692 */
693function showAlert(elementId, message, type) {
694	var alertBox = $('#' + elementId);
695	alertBox.removeClass('d-none alert-success alert-danger alert-warning').addClass('alert-' + type);
696	alertBox.text(message);
697}
698
699// Intercetta il tasto back del browser
700$(window).on('popstate', function (event) {
701	// Qui puoi aggiungere la logica per gestire l'evento back
702	console.log('Tasto back premuto');
703	console.log('URL attuale:', window.location.href);
704
705	// Ricava il valore dopo 'pages/' dall'URL
706	let path = window.location.pathname;
707	let index = path.indexOf('/pages/');
708	if (index !== -1) {
709		let valore = path.substring(index + 7); // Lunghezza di '/pages/'
710		// Estrai il nome della pagina senza .php
711		let pageName = valore.replace('.php', '');
712		// Gestisci i parametri query
713		let urlParams = new URLSearchParams(window.location.search);
714		// Imposta le variabili globali dai parametri
715		if (urlParams.has('idcorso')) {
716			window.idcorso = urlParams.get('idcorso');
717		}
718		if (urlParams.has('idescursione')) {
719			window.idescursione = urlParams.get('idescursione');
720		}
721		if (urlParams.has('biennio')) {
722			window.biennio = urlParams.get('biennio');
723		}
724		if (urlParams.has('idsocio')) {
725			window.idsocio = urlParams.get('idsocio');
726		}
727		if (urlParams.has('azione')) {
728			window.azione = urlParams.get('azione');
729		}
730		if (urlParams.has('keycorso')) {
731			window.keycorso = urlParams.get('keycorso');
732		}
733		if (urlParams.has('codiceEsito')) {
734			window.codiceEsito = urlParams.get('codiceEsito');
735		}
736		if (urlParams.has('esito')) {
737			window.esito = urlParams.get('esito');
738		}
739		if (urlParams.has('codTrans')) {
740			window.codTrans = urlParams.get('codTrans');
741		}
742		if (urlParams.has('descrizione')) {
743			window.descrizione = urlParams.get('descrizione');
744		}
745		cambia_pag(pageName, '', 'popstate');
746	} else {
747		console.log('Nessun valore trovato dopo pages/');
748	}
749
750});
751
752/**
753 * Mostra le informazioni sulla pagina corrente in un modale.
754 */
755function showInfo() {
756	const pageDescriptions = {
757		'homepage': 'Questa pagina mostra la homepage dell\'area riservata. Qui puoi vedere un riepilogo delle tue attività, notifiche e collegamenti rapidi alle sezioni principali.',
758		'socio': 'In questa pagina puoi visualizzare e modificare i tuoi dati personali come nome, indirizzo, contatti e altre informazioni del profilo socio.',
759		'corsi_socio': 'Qui trovi la lista dei corsi a cui sei iscritto o hai partecipato. Puoi visualizzare dettagli, attestati e gestire iscrizioni.',
760		'escursioni_socio': 'Visualizza le escursioni a cui hai partecipato o sei iscritto. Include dettagli su date, luoghi e guide.',
761		'escursioni_socio_cammina_natura': 'Visualizza le escursioni dell\'edizione corrente di Cammina Natura in cui sei coinvolto.',
762		'pagamento': 'Gestisci i pagamenti per corsi, escursioni o rinnovi. Puoi effettuare pagamenti online e visualizzare lo storico.',
763		'prodotti': 'Acquista prodotti dell\'AIGAE come gadget, libri o materiali escursionistici direttamente dall\'area riservata.',
764		'ordini': 'Visualizza gli ordini effettuati per i prodotti acquistati. Puoi vedere i dettagli degli acquisti completati.',
765		'crediti': 'Visualizza e gestisci i tuoi crediti formativi accumulati attraverso corsi e attività.',
766		'rinnovo': 'Effettua il rinnovo della tua tessera associativa annuale.',
767		'assicurazione': 'Visualizza e scarica la tua polizza assicurativa valida per le attività associative.',
768		'lista_attestati': 'Scarica gli attestati di partecipazione ai corsi e alle escursioni completate.',
769		'card': 'Acquista le card Assicurazione',
770		'gest_corsi_direttore': 'Se sei un direttore di corso, qui puoi gestire i tuoi corsi: visualizzare iscrizioni, partecipanti, materiali. Nella sezione partecipanti, puoi filtrare la lista per accettati/idonei utilizzando i pulsanti di filtro, rimuovere iscritti dal corso e modificare lo stato di accettazione e id
770oneità cliccando sui badge corrispondenti.',
771		'nuova_escursione': 'Crea e organizza nuove escursioni, specificando date, luoghi, guide e dettagli logistici.',
772		'nuova_escursione_cammina_natura': 'Inserisci un\'escursione gratuita per l\'edizione corrente di Cammina Natura.',
773		'escursione': 'Visualizza i dettagli di una specifica escursione, inclusi partecipanti e materiali.',
774		'crediti_richiesti': 'Visualizza le richieste di crediti formative inviate e il loro stato.',
775		'richiesta_crediti_soci': 'Invia richieste per il riconoscimento di crediti formativi da attività esterne.',
776		'pagamento_corso': 'Effettua il pagamento per un corso specifico selezionato.',
777		'cms': 'Contenuti informativi, come news, annunci o informazioni generali.',
778		'gestione_mail': 'Gestisci le tue preferenze per le comunicazioni email e newsletter.',
779		'fatture': 'Questa pagina permette di visualizzare la lista delle transazioni di pagamento in una tabella e scaricare le fatture relative ai pagamenti effettuati per i vari anni. Puoi filtrare la tabella per anno utilizzando il menu a tendina.',
780		'invio_mail_corsi': 'Questa pagina permette di selezionare i partecipanti a un corso e inviare loro email personalizzate. Seleziona i destinatari spuntando le caselle, componi il messaggio e invia.',
781	};
782
783	const pageButtons = {
784		'homepage': [
785			{ label: 'Accedi ai Crediti', desc: 'Vai alla pagina per gestire i crediti formativi.' },
786			{ label: 'Rinnova Ora', desc: 'Procedi con il pagamento per il rinnovo della tessera.' },
787			{ label: 'Visualizza Assicurazione', desc: 'Vai alla pagina con le informazioni assicurative.' },
788			{ label: 'Scarica Fattura/Ricevuta', desc: 'Scarica il documento fiscale relativo al pagamento.' }
789		],
790		'socio': [
791			{ label: 'Salva', desc: 'Salva le modifiche apportate ai tuoi dati personali.' },
792			{ label: 'Visualizza (occhio)', desc: 'Visualizza il documento caricato.' },
793			{ label: 'Modifica (matita)', desc: 'Modifica o sostituisci il documento.' },
794			{ label: 'Elimina (cestino)', desc: 'Elimina il documento caricato.' },
795			{ label: 'Aggiungi (+)', desc: 'Carica un nuovo documento.' }
796		],
797		'crediti': [
798			{ label: 'Indietro', desc: 'Torna alla visualizzazione precedente.' },
799			{ label: 'BIENNIO X/Y', desc: 'Visualizza i crediti relativi al biennio selezionato.' },
800			{ label: 'Richiedi Crediti Formativi', desc: 'Vai alla pagina per inserire una nuova richiesta di crediti.' },
801			{ label: 'Crediti in attesa di Approvazione', desc: 'Visualizza lo stato delle tue richieste di crediti.' }
802		],
803		'pagamento': [
804			{ label: 'Procedi con il pagamento', desc: 'Avvia la procedura di pagamento sicuro.' },
805			{ label: 'Torna alla home', desc: 'Ritorna alla homepage dell\'area riservata.' }
806		],
807		'fatture': [
808			{ label: 'Filtra per anno', desc: 'Utilizza il menu a tendina per filtrare le transazioni per anno specifico.' },
809			{ label: 'Scarica Fattura', desc: 'Scarica la fattura annuale per l\'anno selezionato.' }
810		],
811		'gest_corsi_direttore': [
812			{ label: 'Partecipanti (X)', desc: 'Visualizza la lista dei partecipanti iscritti al corso selezionato.' },
813			{ label: 'Elimina (cestino rosso)', desc: 'Rimuovi un partecipante dal corso. Verrà richiesta conferma prima della rimozione.' }
814		],
815		'invio_mail_corsi': [
816			{ label: 'Seleziona Tutti', desc: 'Seleziona tutti i partecipanti nella lista.' },
817			{ label: 'Deseleziona Tutti', desc: 'Deseleziona tutti i partecipanti.' },
818			{ label: 'Invia Email', desc: 'Apri il modale per comporre e inviare l\'email ai selezionati. Puoi allegare file alla mail.' }
819		]
820	};
821
822	let content = '<p>' + (pageDescriptions[window.currentPage] || 'Descrizione non disponibile per questa pagina.') + '</p>';
823
824	if (pageButtons[window.currentPage]) {
825		content += '<hr><h5>Funzionalità Pulsanti:</h5><ul class="list-group list-group-flush">';
826		pageButtons[window.currentPage].forEach(btn => {
827			content += `<li class="list-group-item"><strong>${btn.label}:</strong> ${btn.desc}</li>`;
828		});
829		content += '</ul>';
830	}
831
832	$('#infoModalBody').html(content);
833	const modal = new bootstrap.Modal(document.getElementById('infoModal'));
834	modal.show();
835}
836
837function showAssicurazioneInfo() {
838	$('#assicurazioneModal').modal('show');
839}
840
841function showIdentitaeInfo() {
842	const content = '<p>Qui puoi caricare separatamente il fronte e il retro del tuo documento oppure un unico file.</p>';
843	$('#infoModalLabel').text('Informazioni su Documenti identità');
844	$('#infoModalBody').html(content);
845	const modal = new bootstrap.Modal(document.getElementById('infoModal'));
846	modal.show();
847}
848
849function modificaOAggiungi(tipo, num = null) {
850	isModifica = true;
851	let id = 'file_upload_' + tipo;
852	let name = 'file_' + tipo;
853	if ((tipo === 'doc' || tipo === 'req') && num) {
854		name += num;
855	}
856
857	console.log("Modifica/Aggiungi file:", tipo, id, name);
858
859	if (tipo === 'blsd' || tipo === 'cert')
860	{
861		// Apri modal per attestati
862		document.getElementById('tipoCertificato').value = tipo;
863		document.getElementById('enteCertificato').value = '';
864		document.getElementById('dataInizioCertificato').value = '';
865		document.getElementById('dataFineCertificato').value = '';
866		document.getElementById('fileCertificato').value = '';
867		document.getElementById('modalCertificatoLabel').textContent = tipo === 'blsd' ? 'Carica Attestato BLSD' : 'Carica Attestato Primo Soccorso';
868
869		jQuery('#modalCertificato').modal('show');
870
871		// Re-inizializza datepicker dentro il modal per garantire funzionamento con zoom
872		jQuery('#modalCertificato').on('shown.bs.modal', function () {
873			var $modal = jQuery(this);
874			jQuery('#dataInizioCertificato, #dataFineCertificato').datepicker('destroy').datepicker({
875				dateFormat: 'dd/mm/yy',
876				changeMonth: true,
877				changeYear: true,
878				yearRange: '-100:+10',
879				beforeShow: function (input, inst) {
880					// Appendi il datepicker dentro il modal body per posizionamento corretto con zoom
881					setTimeout(function () {
882						var $dp = inst.dpDiv;
883						$dp.css('z-index', 1065);
884						$modal.find('.modal-body').append($dp);
885						// Ricalcola posizione relativa all'input
886						var $input = jQuery(input);
887						var inputOffset = $input.position();
888						$dp.css({
889							position: 'absolute',
890							top: inputOffset.top + $input.outerHeight(),
891							left: inputOffset.left
892						});
893					}, 0);
894				}
895			});
896		});
897
898		return;
899	}
900
901	// Se si modifica il documento BLSD o Certificato, svuota i campi collegati (per altri tipi)
902	if (tipo === 'blsd') {
903		document.getElementById('blsd_rilasciato_ente').value = '';
904		document.getElementById('blsd_rilasciato_data_inizio').value = '';
905		document.getElementById('blsd_rilasciato_data_fine').value = '';
906	} else if (tipo === 'cert') {
907		document.getElementById('soccorso_rilasciato_ente').value = '';
908		document.getElementById('soccorso_rilasciato_data_inizio').value = '';
909		document.getElementById('soccorso_rilasciato_data_fine').value = '';
910	}
911
912	document.getElementById(id).name = name;
913	document.getElementById(id).click();
914}
915
916function uploadFotoHome() {
917	const fileInput = document.getElementById('file_foto_home');
918
919	const file = fileInput.files[0];
920	if (!file) return;
921
922	if(!checkFileSize(fileInput))
923		return;
924
925	const formData = new FormData();
926	formData.append('file_foto', file);
927
928	$.ajax({
929		url: '/area_riservata/lib/api/api_interne.php?tipo_api=upload_foto',
930		type: 'POST',
931		data: formData,
932		processData: false,
933		contentType: false,
934		success: function(response) {
935			if (response.success) {
936				showBootstrapAlert('Foto caricata con successo! In attesa di approvazione.', 'success');
937				// Reload page or update UI
938				setTimeout(() => location.reload(), 2000);
939			} else {
940				showBootstrapAlert('Errore nel caricamento: ' + response.message, 'danger');
941			}
942		},
943		error: function(xhr, status, error) {
944			showBootstrapAlert('Errore di connessione.', 'danger');
945		}
946	});
947}
948
949function updateFotoHome() {
950	
951}
952
953function togglePasswordVisibility() {
954	var passwordInput = document.getElementById('password');
955	var icon = document.querySelector('#password ~ .material-icons');
956	if (passwordInput.type === 'password') {
957		passwordInput.type = 'text';
958		icon.textContent = 'visibility_off';
959	} else {
960		passwordInput.type = 'password';
961		icon.textContent = 'visibility';
962	}
963}
964
965function getRinnovoDate()
966{
967	return "-01-02 10:00";
968}
969
970function getDeviceType() {
971    const ua = navigator.userAgent;
972    if (/android/i.test(ua)) {
973        return 'android';
974    } else if (/iPad|iPhone|iPod/.test(ua)) {
975        return 'ios';
976    } else {
977        return 'desktop';
978    }
979}
980
981function showPWAPopup() {
982    if (!localStorage.getItem('pwa_popup_shown')) {
983        const device = getDeviceType();
984        let instructions = '';
985        if (device === 'ios') {
986            instructions = "Per installare la Web app evoluta, apri Safari, tocca il pulsante Condividi (icona quadrata con freccia), poi seleziona 'Aggiungi alla schermata Home'.";
987        } else if (device === 'android') {
988            instructions = "Per installare la Web app evoluta, apri Chrome, tocca il menu (tre punti), poi seleziona 'Aggiungi alla schermata Home' o 'Installa app'.";
989        } else {
990            instructions = "Per installare la Web app evoluta, clicca sull'icona di installazione nella barra degli indirizzi del browser.";
991        }
992        $('#pwaInstallModal .modal-body').html(instructions);
993        $('#pwaInstallModal').modal('show');
994        localStorage.setItem('pwa_popup_shown', 'true');
995    }
996}

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.