Files
gianca-s-event/script.js
2026-03-27 17:48:45 +01:00

221 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const form = document.getElementById('rsvp-form');
const statusNode = document.getElementById('form-status');
const attendanceFields = document.getElementById('attendance-fields');
const attendanceInputs = Array.from(document.querySelectorAll('input[name="attendance"]'));
const successModal = document.getElementById('success-modal');
const successOkButton = document.getElementById('success-ok');
const closeModalNodes = Array.from(document.querySelectorAll('[data-close-modal]'));
const googleCalendarLink = document.getElementById('google-calendar-link');
const iCalDownloadButton = document.getElementById('ical-download');
const copyIbanButton = document.getElementById('copy-iban');
const ibanFeedback = document.getElementById('iban-feedback');
const giftHolder = document.getElementById('gift-holder');
const giftIban = document.getElementById('gift-iban');
const giftCausal = document.getElementById('gift-causal');
const giftNote = document.getElementById('gift-note');
// Modifica qui i dati del calendario evento.
const EVENT_CALENDAR = {
title: 'Il Gianquarantesimo',
location: 'Lost Paradise Beach Club, Bacoli',
description: 'Conferma la tua presenza per i 40 anni del Gianca.',
date: '2026-04-25',
startTime: '12:00',
durationHours: 6,
timezone: 'Europe/Rome'
};
// Modifica qui i dati regalo / quota viaggio.
const GIFT_DETAILS = {
holder: 'Flygo S.r.l',
iban: 'IT 34 O 02008 03450 000011029239',
causal: 'Lista Compleanno Giancarlo Esposito da parte di ...',
note: 'Nota facoltativa: un pensiero semplice e sempre gradito.'
};
function updateAttendanceFields() {
const selected = document.querySelector('input[name="attendance"]:checked');
const attending = selected?.value === 'si';
attendanceFields.classList.toggle('attendance-fields--hidden', !attending);
attendanceFields.querySelectorAll('input, select, textarea').forEach((field) => {
field.disabled = !attending;
if (!attending && field.tagName === 'TEXTAREA') field.value = '';
if (!attending && field.tagName === 'SELECT') field.value = '0';
});
}
function openSuccessModal() {
if (!successModal) return;
successModal.classList.add('success-modal--open');
successModal.setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
successOkButton?.focus();
}
function closeSuccessModal() {
if (!successModal) return;
successModal.classList.remove('success-modal--open');
successModal.setAttribute('aria-hidden', 'true');
document.body.classList.remove('modal-open');
}
function pad(value) {
return String(value).padStart(2, '0');
}
function createFloatingDateTime(date, time, plusHours = 0) {
const [year, month, day] = date.split('-').map(Number);
const [hours, minutes] = time.split(':').map(Number);
const normalizedDate = new Date(Date.UTC(year, month - 1, day, hours, minutes, 0));
normalizedDate.setUTCHours(normalizedDate.getUTCHours() + plusHours);
return `${normalizedDate.getUTCFullYear()}${pad(normalizedDate.getUTCMonth() + 1)}${pad(normalizedDate.getUTCDate())}T${pad(normalizedDate.getUTCHours())}${pad(normalizedDate.getUTCMinutes())}00`;
}
function buildGoogleCalendarUrl(eventData) {
const start = createFloatingDateTime(eventData.date, eventData.startTime, 0);
const end = createFloatingDateTime(eventData.date, eventData.startTime, eventData.durationHours);
const params = new URLSearchParams({
action: 'TEMPLATE',
text: eventData.title,
details: eventData.description,
location: eventData.location,
ctz: eventData.timezone,
dates: `${start}/${end}`
});
return `https://calendar.google.com/calendar/render?${params.toString()}`;
}
function escapeIcsText(value) {
return value
.replace(/\\/g, '\\\\')
.replace(/\n/g, '\\n')
.replace(/,/g, '\\,')
.replace(/;/g, '\\;');
}
function buildIcsContent(eventData) {
const start = createFloatingDateTime(eventData.date, eventData.startTime, 0);
const end = createFloatingDateTime(eventData.date, eventData.startTime, eventData.durationHours);
const stamp = `${createFloatingDateTime(eventData.date, eventData.startTime, 0)}Z`;
const uid = `gianca-40-${start}@gianca-event`;
return [
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//Gianca40//Event Landing//IT',
'CALSCALE:GREGORIAN',
'BEGIN:VEVENT',
`UID:${uid}`,
`DTSTAMP:${stamp}`,
`DTSTART;TZID=${eventData.timezone}:${start}`,
`DTEND;TZID=${eventData.timezone}:${end}`,
`SUMMARY:${escapeIcsText(eventData.title)}`,
`LOCATION:${escapeIcsText(eventData.location)}`,
`DESCRIPTION:${escapeIcsText(eventData.description)}`,
'END:VEVENT',
'END:VCALENDAR'
].join('\r\n');
}
function triggerIcsDownload() {
const content = buildIcsContent(EVENT_CALENDAR);
const blob = new Blob([content], { type: 'text/calendar;charset=utf-8' });
const downloadUrl = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = 'i-40-anni-del-gianca.ics';
document.body.append(link);
link.click();
link.remove();
URL.revokeObjectURL(downloadUrl);
}
function setIbanFeedback(message) {
if (!ibanFeedback) return;
ibanFeedback.textContent = message;
}
async function copyIbanToClipboard() {
if (!copyIbanButton) return;
const ibanNodeId = copyIbanButton.dataset.copyTarget;
const ibanText = document.getElementById(ibanNodeId || '')?.textContent?.trim();
if (!ibanText) return;
try {
await navigator.clipboard.writeText(ibanText);
setIbanFeedback('IBAN copiato negli appunti.');
} catch (error) {
const fallbackField = document.createElement('input');
fallbackField.value = ibanText;
document.body.append(fallbackField);
fallbackField.select();
const copied = document.execCommand('copy');
fallbackField.remove();
setIbanFeedback(copied ? 'IBAN copiato negli appunti.' : 'Copia non riuscita. Riprova.');
}
}
attendanceInputs.forEach((input) => input.addEventListener('change', updateAttendanceFields));
closeModalNodes.forEach((node) => node.addEventListener('click', closeSuccessModal));
successOkButton?.addEventListener('click', closeSuccessModal);
iCalDownloadButton?.addEventListener('click', triggerIcsDownload);
copyIbanButton?.addEventListener('click', async () => {
await copyIbanToClipboard();
window.clearTimeout(copyIbanButton.dataset.feedbackTimeoutId);
const timeoutId = window.setTimeout(() => setIbanFeedback(''), 2500);
copyIbanButton.dataset.feedbackTimeoutId = String(timeoutId);
});
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && successModal?.classList.contains('success-modal--open')) {
closeSuccessModal();
}
});
updateAttendanceFields();
if (googleCalendarLink) {
googleCalendarLink.href = buildGoogleCalendarUrl(EVENT_CALENDAR);
}
if (giftHolder) giftHolder.textContent = GIFT_DETAILS.holder;
if (giftIban) giftIban.textContent = GIFT_DETAILS.iban;
if (giftCausal) giftCausal.textContent = GIFT_DETAILS.causal;
if (giftNote) giftNote.textContent = GIFT_DETAILS.note;
function encode(data) {
return new URLSearchParams(data).toString();
}
form?.addEventListener('submit', async (event) => {
event.preventDefault();
if (!form.reportValidity()) return;
const submitButton = form.querySelector('button[type="submit"]');
const formData = new FormData(form);
submitButton.disabled = true;
statusNode.textContent = 'Invio in corso...';
try {
const response = await fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: encode(formData)
});
if (!response.ok) {
throw new Error('Submission failed');
}
form.reset();
updateAttendanceFields();
statusNode.textContent = '';
openSuccessModal();
} catch (error) {
statusNode.textContent = 'Cè stato un problema nellinvio. Riprova tra poco.';
} finally {
submitButton.disabled = false;
}
});