From 78d41daf4feb42c82523c4aa5953fced865b433c Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Sun, 6 Sep 2026 14:44:29 +0200 Subject: [PATCH] Ritarda di 10 secondi la notifica di prova, per poter chiudere l'app. Il pulsante si preme con l'app aperta, quindi la push arrivava sempre in primo piano: l'unico caso che non serve provare. Ora la route aspetta `ritardoMs` (10s di default, 25 al massimo) prima di inviare, e il toast dice di chiudere l'app subito. L'attesa tiene aperta la funzione, quindi il tetto e' la durata massima concessa dall'hosting: annotato come ponytail nel codice. Co-Authored-By: Claude Opus 5 --- docs/modules/notifiche.md | 4 +++- src/lib/push-client.ts | 12 ++++++++---- src/routes/api/public/push-prova.ts | 16 +++++++++++++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/modules/notifiche.md b/docs/modules/notifiche.md index 24feacb..7972a57 100644 --- a/docs/modules/notifiche.md +++ b/docs/modules/notifiche.md @@ -60,7 +60,9 @@ copre in particolare le sessioni lunghe della webapp (vedi il della risposta del servizio push, più se l'endpoint risulta in `push_subscriptions`. Serve a rendere osservabile un "non arriva": senza, ogni prova richiede un admin, un evento nello stato giusto e una seconda persona. Il pulsante sta in Profilo → Opzioni, sotto - l'interruttore, e compare solo a notifiche attive. + l'interruttore, e compare solo a notifiche attive. L'invio parte dopo 10 secondi + (`ritardoMs`, max 25): premendo il pulsante l'app è per forza aperta, e senza attesa si + proverebbe solo il caso che già funziona. - **`apri-sondaggio`** — premuto da un admin dalla pagina partita: manda a **tutti** i dispositivi iscritti l'avviso di apertura del sondaggio pre-partita (vedi [Scout Live](scout-live.md)). diff --git a/src/lib/push-client.ts b/src/lib/push-client.ts index db6393e..039ddc8 100644 --- a/src/lib/push-client.ts +++ b/src/lib/push-client.ts @@ -84,10 +84,11 @@ export async function attivaNotifiche(giocatoreId: string): Promise { * Manda una push di prova a questo dispositivo e racconta com'è andata. * * Esiste perché "non arriva" è un sintomo cieco: senza, ogni prova richiede un admin, un - * evento nello stato giusto e una seconda persona. L'invio è immediato: per verificare - * l'arrivo ad app chiusa serve invece un invio da un altro dispositivo. + * evento nello stato giusto e una seconda persona. Il server aspetta `ritardoMs` prima di + * inviare: premendo il pulsante l'app è per forza aperta, e senza attesa si proverebbe + * solo il caso che già funziona. */ -export async function notificaDiProva(): Promise<{ +export async function notificaDiProva(ritardoMs?: number): Promise<{ nelDatabase: boolean; stato: number; corpo: string; @@ -100,7 +101,10 @@ export async function notificaDiProva(): Promise<{ const res = await fetch("/api/public/push-prova", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ endpoint: sub.endpoint }), + body: JSON.stringify({ + endpoint: sub.endpoint, + ...(ritardoMs === undefined ? {} : { ritardoMs }), + }), }); if (!res.ok) throw new Error("Prova non riuscita"); return (await res.json()) as { nelDatabase: boolean; stato: number; corpo: string }; diff --git a/src/routes/api/public/push-prova.ts b/src/routes/api/public/push-prova.ts index 63a75cf..2b4e5cc 100644 --- a/src/routes/api/public/push-prova.ts +++ b/src/routes/api/public/push-prova.ts @@ -2,7 +2,13 @@ import { createFileRoute } from "@tanstack/react-router"; import { z } from "zod"; import { inviaPush } from "@/lib/webpush.server"; -const schema = z.object({ endpoint: z.string().url().max(1000) }); +/** Quanto aspettare prima di mandare davvero, per dare il tempo di chiudere l'app. */ +const RITARDO_PREDEFINITO_MS = 10_000; + +const schema = z.object({ + endpoint: z.string().url().max(1000), + ritardoMs: z.number().int().min(0).max(25_000).optional(), +}); /** * Manda una push di prova al dispositivo che la chiede, e racconta com'è andata. @@ -14,6 +20,10 @@ const schema = z.object({ endpoint: z.string().url().max(1000) }); * `push_subscriptions` — cioè se il server sta parlando con questo telefono o con una * vecchia iscrizione morta. * + * L'invio è ritardato di qualche secondo: premendo il pulsante l'app è per forza aperta, + * quindi senza attesa la notifica arriverebbe sempre in primo piano — cioè nell'unico caso + * che non serve provare. + * * Nessun controllo di accesso, come per `push-config` e `push-subscribe`: manda solo * all'endpoint che il chiamante fornisce, quindi al massimo si sveglia da solo. È un URL * segreto per dispositivo, e chi lo conosce lo ha già. @@ -42,6 +52,10 @@ export const Route = createFileRoute("/api/public/push-prova")({ }); } + // ponytail: la funzione resta aperta per il ritardo, semplice ma limitato dal + // tetto di durata dell'hosting. Se servisse aspettare di più, ci vuole una coda. + await new Promise((r) => setTimeout(r, parsed.data.ritardoMs ?? RITARDO_PREDEFINITO_MS)); + const { stato, corpo } = await inviaPush( iscrizione, "🔔 Notifica di prova",