Sondaggio cacche: classifica completa per tutti i giocatori
Elenco con posizioni a pari merito senza salti, barra proporzionale e riga personale evidenziata, anche a sondaggio chiuso. Sezione «Report tecnico» della partita rinominata «Scout». Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a7b9affbd6
commit
91ac7ce65c
4 files changed
+76
-19
No files matched your search
@@ -13,6 +13,12 @@ versioni `0.y.z` erano pre-release.
|
|||||||
|
|
||||||
## [Non rilasciato]
|
## [Non rilasciato]
|
||||||
|
|
||||||
|
### Modificato
|
||||||
|
|
||||||
|
- Sondaggio cacche: la classifica completa è visibile a tutti i giocatori, anche a sondaggio
|
||||||
|
chiuso, con posizioni a pari merito senza salti (1°, 1°, 2°) e la propria riga evidenziata.
|
||||||
|
- Pagina partita: la sezione «Report tecnico» si chiama «Scout».
|
||||||
|
|
||||||
## [1.6.0] - 2026-11-02
|
## [1.6.0] - 2026-11-02
|
||||||
|
|
||||||
Voto MVP definitivo e segreto, Scout live a valutazioni. Cinque migration, da `m35` a `m39`,
|
Voto MVP definitivo e segreto, Scout live a valutazioni. Cinque migration, da `m35` a `m39`,
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ Senza punteggio, `chiudiSet()` chiude il set (come 0-0) se ha almeno una valutaz
|
|||||||
parziali se ha dati (`parzialiFinali()`, `scout-store.ts`). Con nessuna valutazione risponde
|
parziali se ha dati (`parzialiFinali()`, `scout-store.ts`). Con nessuna valutazione risponde
|
||||||
«Nessun set da salvare». Una partita senza punti ha parziali 0-0 e **non è un risultato**:
|
«Nessun set da salvare». Una partita senza punti ha parziali 0-0 e **non è un risultato**:
|
||||||
`haPunteggio()` la esclude da Home, Classifica e dalla pagina della partita, dove non sostituisce il
|
`haPunteggio()` la esclude da Home, Classifica e dalla pagina della partita, dove non sostituisce il
|
||||||
referto CSI; resta visibile il «Report tecnico» con il CSV.
|
referto CSI; resta visibile il «Scout» con il CSV.
|
||||||
|
|
||||||
`finePartita()` (`scout.tsx`) compone i parziali finali, inserisce la partita in
|
`finePartita()` (`scout.tsx`) compone i parziali finali, inserisce la partita in
|
||||||
`scout_partite` (INSERT, non upsert), poi cancella la riga da `scout_live` (stato consumato)
|
`scout_partite` (INSERT, non upsert), poi cancella la riga da `scout_live` (stato consumato)
|
||||||
@@ -122,7 +122,7 @@ e rilascia la sessione.
|
|||||||
`scout-export.ts` genera un CSV (separatore `;`, BOM UTF-8) con parziali, riepilogo per giocatore e
|
`scout-export.ts` genera un CSV (separatore `;`, BOM UTF-8) con parziali, riepilogo per giocatore e
|
||||||
log cronologico delle azioni. Se ci sono valutazioni, aggiunge una tabella per set e giocatore con
|
log cronologico delle azioni. Se ci sono valutazioni, aggiunge una tabella per set e giocatore con
|
||||||
i conteggi di «più» e «meno» di ogni fondamentale (solo per chi ne ha). Scaricabile dagli admin dalla
|
i conteggi di «più» e «meno» di ogni fondamentale (solo per chi ne ha). Scaricabile dagli admin dalla
|
||||||
pagina partita, sezione "Report tecnico".
|
pagina partita, sezione "Scout".
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ calcolati a runtime).
|
|||||||
- Le valutazioni dei set chiusi e delle partite finite sono salvate ma non si rivedono nell'app: lo
|
- Le valutazioni dei set chiusi e delle partite finite sono salvate ma non si rivedono nell'app: lo
|
||||||
scout mostra solo il set in corso e l'unica lettura è il CSV admin. Evoluzione: tabella nella
|
scout mostra solo il set in corso e l'unica lettura è il CSV admin. Evoluzione: tabella nella
|
||||||
pagina partita.
|
pagina partita.
|
||||||
- Il blocco «Report tecnico» della pagina partita mostra ancora Punti/Ace/Muri/Errori (a zero per le
|
- Il blocco «Scout» della pagina partita mostra ancora Punti/Ace/Muri/Errori (a zero per le
|
||||||
partite di sole valutazioni) e non le valutazioni, che sono solo nel CSV admin.
|
partite di sole valutazioni) e non le valutazioni, che sono solo nel CSV admin.
|
||||||
- Scout aperto a tutta la squadra: nessun filtro su chi può registrare le azioni, l'unica
|
- Scout aperto a tutta la squadra: nessun filtro su chi può registrare le azioni, l'unica
|
||||||
garanzia è il lock di sessione (vedi sopra).
|
garanzia è il lock di sessione (vedi sopra).
|
||||||
|
|||||||
@@ -40,11 +40,15 @@ export function SondaggioCacche({
|
|||||||
const media = mediaPartita(righe, eventoId);
|
const media = mediaPartita(righe, eventoId);
|
||||||
const classifica = [...dellaPartita]
|
const classifica = [...dellaPartita]
|
||||||
.sort((a, b) => b.quantita - a.quantita)
|
.sort((a, b) => b.quantita - a.quantita)
|
||||||
.slice(0, 3)
|
|
||||||
.map((r) => {
|
.map((r) => {
|
||||||
const g = squadra.find((g) => g.id === r.giocatore_id);
|
const g = squadra.find((g) => g.id === r.giocatore_id);
|
||||||
return { ...r, nome: g ? nomeCompleto(g) : "—" };
|
return { ...r, nome: g ? nomeCompleto(g) : "—" };
|
||||||
});
|
})
|
||||||
|
// Pari merito = stessa posizione, senza salti (1°, 1°, 2°).
|
||||||
|
.map((r, _, tutti) => ({
|
||||||
|
...r,
|
||||||
|
pos: new Set(tutti.filter((t) => t.quantita > r.quantita).map((t) => t.quantita)).size + 1,
|
||||||
|
}));
|
||||||
|
|
||||||
async function rispondi(quantita: number) {
|
async function rispondi(quantita: number) {
|
||||||
if (!io) return;
|
if (!io) return;
|
||||||
@@ -89,6 +93,7 @@ export function SondaggioCacche({
|
|||||||
? "Sondaggio chiuso: era aperto fino al fischio d'inizio."
|
? "Sondaggio chiuso: era aperto fino al fischio d'inizio."
|
||||||
: "Apre alle 8:00 del giorno della partita: riceverai una notifica."}
|
: "Apre alle 8:00 del giorno della partita: riceverai una notifica."}
|
||||||
</p>
|
</p>
|
||||||
|
<Classifica righe={classifica} io={io?.id} media={media} />
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -126,19 +131,7 @@ export function SondaggioCacche({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-3 flex flex-wrap items-center gap-2 text-[13px]">
|
<Classifica righe={classifica} io={io?.id} media={media} />
|
||||||
<span className="rounded-full bg-secondary px-2.5 py-1 font-semibold">
|
|
||||||
Media squadra {media}
|
|
||||||
</span>
|
|
||||||
{classifica.map((r, i) => (
|
|
||||||
<span
|
|
||||||
key={r.giocatore_id}
|
|
||||||
className="rounded-full bg-secondary px-2.5 py-1 font-semibold"
|
|
||||||
>
|
|
||||||
{i === 0 ? "🥇" : i === 1 ? "🥈" : "🥉"} {r.nome} · {r.quantita}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{admin ? (
|
{admin ? (
|
||||||
<button
|
<button
|
||||||
@@ -154,3 +147,61 @@ export function SondaggioCacche({
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MEDAGLIE = ["🥇", "🥈", "🥉"];
|
||||||
|
|
||||||
|
type RigaClassifica = { giocatore_id: string; nome: string; quantita: number; pos: number };
|
||||||
|
|
||||||
|
function Classifica({
|
||||||
|
righe,
|
||||||
|
io,
|
||||||
|
media,
|
||||||
|
}: {
|
||||||
|
righe: RigaClassifica[];
|
||||||
|
io: string | undefined;
|
||||||
|
media: number | string;
|
||||||
|
}) {
|
||||||
|
if (righe.length === 0) return null;
|
||||||
|
const max = Math.max(...righe.map((r) => r.quantita), 1);
|
||||||
|
return (
|
||||||
|
<div className="mt-4">
|
||||||
|
<div className="mb-2 flex items-center justify-between text-[13px]">
|
||||||
|
<span className="font-bold uppercase tracking-wide text-muted-foreground">Classifica</span>
|
||||||
|
<span className="rounded-full bg-secondary px-2.5 py-1 font-semibold">
|
||||||
|
Media squadra {media}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ol className="divide-y divide-border overflow-hidden rounded-2xl bg-secondary/60">
|
||||||
|
{righe.map((r) => (
|
||||||
|
<li
|
||||||
|
key={r.giocatore_id}
|
||||||
|
className={cn(
|
||||||
|
"relative flex items-center gap-3 px-3 py-2.5",
|
||||||
|
r.giocatore_id === io && "bg-accent/15",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden
|
||||||
|
className="absolute inset-y-0 left-0 bg-accent/10"
|
||||||
|
style={{ width: `${(r.quantita / max) * 100}%` }}
|
||||||
|
/>
|
||||||
|
<span className="relative w-7 text-center text-[15px] font-bold tabular-nums text-muted-foreground">
|
||||||
|
{r.pos <= 3 ? MEDAGLIE[r.pos - 1] : `${r.pos}°`}
|
||||||
|
</span>
|
||||||
|
<span className="relative min-w-0 flex-1 truncate text-[15px] font-semibold">
|
||||||
|
{r.nome}
|
||||||
|
{r.giocatore_id === io ? (
|
||||||
|
<span className="ml-1.5 text-[13px] font-bold uppercase text-muted-foreground">
|
||||||
|
tu
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
<span className="relative text-[17px] font-bold tabular-nums">
|
||||||
|
{r.quantita === 5 ? "5+" : r.quantita}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -250,7 +250,7 @@ function PartitaDetail() {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{scout && totaliTeam ? (
|
{scout && totaliTeam ? (
|
||||||
<Section titolo="Report tecnico">
|
<Section titolo="Scout">
|
||||||
<Card>
|
<Card>
|
||||||
<div className="grid grid-cols-4 gap-2 text-center">
|
<div className="grid grid-cols-4 gap-2 text-center">
|
||||||
{[
|
{[
|
||||||
|
|||||||
Reference in new issue
Block a user