Toglie la foto tessera dal profilo (DD-044)

Il Profilo non chiede più la foto tessera e la scheda admin non la mostra.
Il completamento diventa dati personali 34%, documento 33%, certificato 33%.
La migration m29 elimina la colonna profili_giocatore.foto_path; le 4 foto
già caricate sono state cancellate dal bucket profili-giocatore. Migration
applicata in produzione.

Test: pesi e sezioni di profili-core, rendering di CampiProfilo, colonna
rimossa sul database locale. Documentati DD-044, modulo profilo-giocatore,
DATABASE, ROADMAP e changelog.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-10-01 15:03:04 +02:00
1 parent e822e4574b
commit de78431090
21 files changed
+164 -79

No files matched your search

+2 -17
View File
@@ -120,14 +120,12 @@ export function CampiProfilo({
sezioni,
fileDocumento,
fileCertificato,
fileFoto,
}: {
corrente: Profilo;
aggiorna: (patch: Partial<Profilo>) => void;
sezioni: Record<Sezione, boolean>;
fileDocumento?: React.ReactNode;
fileCertificato?: React.ReactNode;
fileFoto?: React.ReactNode;
}) {
return (
<>
@@ -241,14 +239,13 @@ export function CampiProfilo({
/>
</Campo>
{fileCertificato}
{fileFoto}
</>
);
}
/**
* I dati personali dell'allenatore (DD-034): gli stessi campi di `profili_giocatore`, meno
* indirizzo, documento, certificato e foto tessera. Condivisi tra Profilo e dashboard admin.
* indirizzo, documento e certificato. Condivisi tra Profilo e dashboard admin.
*/
export function CampiAllenatore({
corrente,
@@ -469,18 +466,6 @@ export function ProfiloAmministrativo({
onCaricato={caricato("certificatoPath")}
/>
}
fileFoto={
<>
<Intestazione titolo="Foto tessera" completa={sezioni.foto} />
<CampoFile
label="Foto tessera"
path={corrente.fotoPath}
sezione="foto"
giocatoreId={giocatoreId}
onCaricato={caricato("fotoPath")}
/>
</>
}
/>
<button
@@ -550,7 +535,7 @@ export function CompletaProfilo({
<p className="mt-2 text-[13px] text-muted-foreground">
{allenatore
? "Data e luogo di nascita, telefono ed email."
: "Documento, certificato medico e foto tessera servono per il tesseramento CSI."}
: "Documento e certificato medico servono per il tesseramento CSI."}
</p>
</Link>
</Reveal>
-3
View File
@@ -375,7 +375,6 @@ export type Database = {
documento_scadenza: string | null;
documento_tipo: string | null;
email: string | null;
foto_path: string | null;
giocatore_id: string;
indirizzo: string | null;
luogo_nascita: string | null;
@@ -395,7 +394,6 @@ export type Database = {
documento_scadenza?: string | null;
documento_tipo?: string | null;
email?: string | null;
foto_path?: string | null;
giocatore_id: string;
indirizzo?: string | null;
luogo_nascita?: string | null;
@@ -415,7 +413,6 @@ export type Database = {
documento_scadenza?: string | null;
documento_tipo?: string | null;
email?: string | null;
foto_path?: string | null;
giocatore_id?: string;
indirizzo?: string | null;
luogo_nascita?: string | null;
+4 -10
View File
@@ -21,7 +21,6 @@ export type Profilo = {
documentoRetroPath: string | null;
certificatoScadenza: string | null;
certificatoPath: string | null;
fotoPath: string | null;
};
export type RigaProfilo = {
@@ -40,11 +39,10 @@ export type RigaProfilo = {
documento_retro_path: string | null;
certificato_scadenza: string | null;
certificato_path: string | null;
foto_path: string | null;
};
export const COLONNE_PROFILO =
"giocatore_id, data_nascita, luogo_nascita, indirizzo, telefono, email, documento_tipo, documento_numero, documento_rilasciato_da, documento_emissione, documento_scadenza, documento_fronte_path, documento_retro_path, certificato_scadenza, certificato_path, foto_path";
"giocatore_id, data_nascita, luogo_nascita, indirizzo, telefono, email, documento_tipo, documento_numero, documento_rilasciato_da, documento_emissione, documento_scadenza, documento_fronte_path, documento_retro_path, certificato_scadenza, certificato_path";
export function profiloVuoto(giocatoreId: string): Profilo {
return {
@@ -63,7 +61,6 @@ export function profiloVuoto(giocatoreId: string): Profilo {
documentoRetroPath: null,
certificatoScadenza: null,
certificatoPath: null,
fotoPath: null,
};
}
@@ -84,7 +81,6 @@ export function daRigaProfilo(r: RigaProfilo): Profilo {
documentoRetroPath: r.documento_retro_path,
certificatoScadenza: r.certificato_scadenza,
certificatoPath: r.certificato_path,
fotoPath: r.foto_path,
};
}
@@ -111,12 +107,11 @@ export function aRigaProfilo(p: Profilo): RigaProfilo {
documento_retro_path: oNull(p.documentoRetroPath),
certificato_scadenza: oNull(p.certificatoScadenza),
certificato_path: oNull(p.certificatoPath),
foto_path: oNull(p.fotoPath),
};
}
/** Pesi delle sezioni del profilo (docs/modules/profilo-giocatore.md). */
export const PESI = { dati: 30, documento: 30, certificato: 30, foto: 10 } as const;
export const PESI = { dati: 34, documento: 33, certificato: 33 } as const;
export type Sezione = keyof typeof PESI;
@@ -131,7 +126,6 @@ export function sezioniComplete(p: Profilo | null | undefined): Record<Sezione,
p.documentoRetroPath
),
certificato: !!(p?.certificatoScadenza && p.certificatoPath),
foto: !!p?.fotoPath,
};
}
@@ -145,8 +139,8 @@ export function completamento(p: Profilo | null | undefined): number {
}
/**
* L'allenatore compila solo i dati personali ridotti (DD-034): niente indirizzo, documento,
* certificato né foto tessera, che servono al tesseramento dei giocatori.
* L'allenatore compila solo i dati personali ridotti (DD-034): niente indirizzo, documento
* né certificato, che servono al tesseramento dei giocatori.
*/
export const CAMPI_ALLENATORE = ["dataNascita", "luogoNascita", "telefono", "email"] as const;
+1 -1
View File
@@ -70,7 +70,7 @@ export function useSalvaProfilo() {
});
}
export type SezioneFile = "documento-fronte" | "documento-retro" | "certificato" | "foto";
export type SezioneFile = "documento-fronte" | "documento-retro" | "certificato";
const MAX_BYTE = 8 * 1024 * 1024;
const TIPI_AMMESSI = ["image/jpeg", "image/png", "image/webp", "application/pdf"];
-7
View File
@@ -8,7 +8,6 @@ import {
Download,
FileText,
IdCard,
Image,
Loader2,
Lock,
Send,
@@ -487,12 +486,6 @@ function SchedaGiocatore({
stato={certificato}
path={profilo?.certificatoPath ?? null}
/>
<Documento
icona={<Image className="h-3.5 w-3.5" />}
label="Foto"
stato={sezioni.foto ? "presente" : "assente"}
path={profilo?.fotoPath ?? null}
/>
<span
className={cn(
"flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-bold uppercase",