Calendario: si vedono tutti gli orari validi, e il PDF ne fa una pagina ciascuno

Il popup mostrava solo l'orario del momento: chi guarda ad agosto vuole sapere
com'e' settembre per intero, e una griglia sola gli fa credere che valga per
sempre. Ora ci sono tutti quelli non ancora scaduti, ognuno con la sua etichetta
- In vigore, oppure la data da cui parte - e quelli passati spariscono da soli.

Il bottone scarica /calendario/tutti.pdf: un orario per pagina, con le giornate
fuori griglia ripetute su ognuna, perche' un foglio stampato da solo deve bastare
a se stesso. Gli id singoli restano validi per mandarne uno solo.

calendarioDaMostrare (uno) diventa calendariDaMostrare (tutti): una funzione
sola, non due che dicono cose simili - e' lo stesso difetto dei due link della
pagina servizi, che erano due espressioni per lo stesso indirizzo e sono
divergute.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-17 17:22:22 +02:00
parent d03c62641e
commit 69bd17a296
7 changed files with 207 additions and 147 deletions
+26 -10
View File
@@ -24,21 +24,29 @@ const C_BORDO = '#cfc7b8'; // più scuro del fondo delle celle: due lezioni ugua
const C_ACCENTO = '#9c8b70';
const C_ALT = '#f5f3f0';
export const nomeFilePdf = (cal: Calendario): string =>
`insanitylab-calendario-${cal.id}.pdf`;
/** Un solo orario: il nome porta il suo id. Più orari insieme: il nome è generico. */
export const nomeFilePdf = (cals: Calendario[]): string =>
cals.length === 1 ? `insanitylab-calendario-${cals[0].id}.pdf` : 'insanitylab-calendario-class.pdf';
/**
* Genera il PDF e restituisce il file completo. Il documento è una pagina sola: la griglia sta
* in A4 orizzontale, e spezzarla su due pagine renderebbe illeggibile proprio ciò che si va a
* cercare — l'incrocio fra un giorno e un'ora.
* Genera il PDF e restituisce il file completo: **un orario per pagina**.
*
* Ogni griglia sta in una pagina intera perché spezzarla renderebbe illeggibile proprio ciò
* che si va a cercare — l'incrocio fra un giorno e un'ora; e due orari sullo stesso foglio si
* confonderebbero fra loro. Le giornate fuori griglia si ripetono su ogni pagina: un foglio
* stampato da solo deve bastare a sé stesso.
*/
export function generaCalendarioPdf(cal: Calendario, avvisi: AvvisoCalendario[] = []): Promise<Buffer> {
export function generaCalendariPdf(cals: Calendario[], avvisi: AvvisoCalendario[] = []): Promise<Buffer> {
const doc = new PDFDocument({
size: 'A4',
layout: 'landscape',
margin: 32,
info: {
Title: `InsanityLab — ${cal.sala}, ${cal.titolo}`,
// Il titolo è quello che compare nella scheda del lettore PDF e nel nome suggerito dai
// telefoni: con un orario solo dice quale, con più orari dice il periodo coperto.
Title: cals.length === 1
? `InsanityLab — ${cals[0].sala}, ${cals[0].titolo}`
: `InsanityLab — Calendario delle class (${cals.map((c) => c.titolo).join('; ')})`,
Author: 'InsanityLab',
Subject: 'Calendario delle class',
},
@@ -51,6 +59,17 @@ export function generaCalendarioPdf(cal: Calendario, avvisi: AvvisoCalendario[]
doc.on('error', rifiuta);
});
cals.forEach((cal, indice) => {
if (indice > 0) doc.addPage();
disegnaPagina(doc, cal, avvisi);
});
doc.end();
return finito;
}
/** Una pagina: testata, griglia, legenda, giornate fuori griglia, piè di pagina. */
function disegnaPagina(doc: PDFKit.PDFDocument, cal: Calendario, avvisi: AvvisoCalendario[]): void {
const x0 = doc.page.margins.left;
const larghezzaUtile = doc.page.width - doc.page.margins.left - doc.page.margins.right;
@@ -165,7 +184,4 @@ export function generaCalendarioPdf(cal: Calendario, avvisi: AvvisoCalendario[]
);
doc.font('Helvetica').fontSize(7).fillColor(C_ACCENTO)
.text('insanitylab.it', x0, yAvvisi + 14, { width: larghezzaUtile, align: 'right' });
doc.end();
return finito;
}