Copre giocatori-squadra e la scelta dei messaggi push palloni

Estrae in palloni-core.ts la logica pura di push-messaggio e
promemoria-palloni (finora mista alle chiamate Supabase), così da
poterla testare senza scrivere sul database. Aggiunge test per le
funzioni pure di giocatori-squadra.ts, finora senza copertura.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-01 09:39:09 +02:00
co-authored by Claude Sonnet 5
parent aa1c49542b
commit 127e7c76e9
5 changed files with 255 additions and 60 deletions
+5 -13
View File
@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router";
import { completaTurni, eventiPalloni, eventoPrecedente, oggiISO } from "@/lib/palloni-core";
import { completaTurni, destinatariPromemoriaPalloni, oggiISO } from "@/lib/palloni-core";
import { inviaPush } from "@/lib/webpush.server";
import { leggiEventi } from "@/lib/eventi.server";
@@ -18,22 +18,14 @@ export const Route = createFileRoute("/api/public/promemoria-palloni")({
const turni = completaTurni(salvati, eventi);
const oggi = oggiISO();
const destinatari = new Set<string>();
for (const evento of eventiPalloni(eventi)) {
if (evento.data !== oggi) continue;
const incaricato = turni[evento.id];
if (incaricato) destinatari.add(incaricato);
const prima = eventoPrecedente(eventi, evento.id);
const precedente = prima ? turni[prima.id] : undefined;
if (precedente) destinatari.add(precedente);
}
const destinatari = destinatariPromemoriaPalloni(turni, eventi, oggi);
if (destinatari.size === 0) return Response.json({ inviate: 0 });
if (destinatari.length === 0) return Response.json({ inviate: 0 });
const { data: iscrizioni } = await supabaseAdmin
.from("push_subscriptions")
.select("endpoint, giocatore_id")
.in("giocatore_id", [...destinatari]);
.in("giocatore_id", destinatari);
let inviate = 0;
for (const iscrizione of iscrizioni ?? []) {
@@ -56,4 +48,4 @@ export const Route = createFileRoute("/api/public/promemoria-palloni")({
},
},
},
});
});
+6 -34
View File
@@ -1,13 +1,7 @@
import { createFileRoute } from "@tanstack/react-router";
import { z } from "zod";
import { formatData, giocatori } from "@/lib/crapp-data";
import {
completaTurni,
eventiPalloni,
eventoPrecedente,
eventoSuccessivo,
oggiISO,
} from "@/lib/palloni-core";
import { giocatori } from "@/lib/crapp-data";
import { completaTurni, messaggioPalloniOggi, oggiISO } from "@/lib/palloni-core";
import { leggiEventi } from "@/lib/eventi.server";
const schema = z.object({ endpoint: z.string().url().max(1000) });
@@ -40,7 +34,8 @@ export const Route = createFileRoute("/api/public/push-messaggio")({
.eq("endpoint", parsed.data.endpoint)
.maybeSingle();
if (!iscrizione) return Response.json({ title: "CrAPP", body: "Controlla il turno palloni." });
if (!iscrizione)
return Response.json({ title: "CrAPP", body: "Controlla il turno palloni." });
const { data: righe } = await supabaseAdmin
.from("turni_palloni")
@@ -54,31 +49,8 @@ export const Route = createFileRoute("/api/public/push-messaggio")({
const mioId = iscrizione.giocatore_id;
const nome = giocatori.find((g) => g.id === mioId)?.nome ?? "";
for (const evento of eventiPalloni(eventi)) {
if (evento.data !== oggi) continue;
const prima = eventoPrecedente(eventi, evento.id);
if (prima && turni[prima.id] === mioId) {
return Response.json({
title: "Porta i palloni oggi",
body: `${evento.titolo} · ${evento.ora}. I palloni li hai tu dalla volta scorsa.`,
});
}
if (turni[evento.id] === mioId) {
const dopo = eventoSuccessivo(eventi, evento.id);
return Response.json({
title: "Tocca a te prendere i palloni",
body: dopo
? `A fine ${evento.titolo} porta a casa i palloni e riportali il ${formatData(dopo.data)}.`
: `A fine ${evento.titolo} porta a casa i palloni.`,
});
}
}
return Response.json({
title: "CrAPP · Turno palloni",
body: nome ? `${nome}, controlla il turno palloni nel calendario.` : "Controlla il calendario.",
});
return Response.json(messaggioPalloniOggi(turni, eventi, oggi, mioId, nome));
},
},
},
});
});