Refine landing layout: calendar actions and editorial gift section

This commit is contained in:
bisco
2026-03-25 19:37:04 +01:00
parent 8f580745d8
commit eb12dd880d
3 changed files with 484 additions and 18 deletions

138
script.js
View File

@ -5,6 +5,33 @@ const attendanceInputs = Array.from(document.querySelectorAll('input[name="atten
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: 'I 40 anni del Gianca',
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: 'Giancarlo ...',
iban: 'IT00X0000000000000000000000',
causal: 'Regalo 40 anni Gianca',
note: 'Nota facoltativa: un pensiero semplice e sempre gradito.'
};
function updateAttendanceFields() {
const selected = document.querySelector('input[name="attendance"]:checked');
@ -34,15 +61,126 @@ function closeSuccessModal() {
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();