Esercizio 10 - fix e aggiunta es

This commit is contained in:
2026-02-06 12:04:01 +01:00
parent cdcb614da8
commit b14fc4632a
5 changed files with 479 additions and 6 deletions

View File

@@ -188,10 +188,18 @@
<a href="watchlist/index.html" class="card">
<div class="icon">📺</div>
<div class="info">
<h3>Watchlist (Film/Serie) <span class="difficulty medium">Medio</span></h3>
<h3>Watchlist (Film/Serie) <span class="difficulty easy">Facile</span></h3>
<p>Aggiungi film, salva con localStorage, rimuovi dalla lista</p>
</div>
</a>
<a href="spese/index.html" class="card">
<div class="icon">💰</div>
<div class="info">
<h3>Gestore Spese <span class="difficulty easy">Facile</span></h3>
<p>Aggiungi spese per categoria, calcola statistiche, salva e visualizza</p>
</div>
</a>
</div>
</div>
</body>

View File

@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Gestore Spese</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<a href="../index.html" style="position: absolute; top: 20px; left: 20px; text-decoration: none; color: #555; font-weight: bold;">← Dashboard</a>
<h1>💰 Gestore Spese</h1>
<div class="input-group">
<select id="categoria">
<option value="">Categoria</option>
<option value="Cibo">🍔 Cibo</option>
<option value="Trasporti">🚗 Trasporti</option>
<option value="Intrattenimento">🎬 Intrattenimento</option>
<option value="Utenze">💡 Utenze</option>
<option value="Salute">🏥 Salute</option>
<option value="Altro">📦 Altro</option>
</select>
<input type="number" id="importo" placeholder="Importo (€)" min="0" step="0.01">
<input type="text" id="descrizione" placeholder="Descrizione">
<button id="btnAggiungi">Aggiungi</button>
</div>
<div class="stats-box">
<div class="stat">
<span class="stat-label">Totale</span>
<span class="stat-value"><span id="totaleSpese">0.00</span></span>
</div>
<div class="stat">
<span class="stat-label">N° Spese</span>
<span class="stat-value"><span id="numeroSpese">0</span></span>
</div>
<div class="stat">
<span class="stat-label">Media</span>
<span class="stat-value"><span id="mediaSpesa">0.00</span></span>
</div>
</div>
<h2>Spese per Categoria</h2>
<div id="categorieStime">
<!-- Generato dinamicamente -->
</div>
<div class="button-group">
<button id="btnRipristina" class="btn-delete">Elimina Tutte</button>
</div>
<script src="script.js"></script>
</body>
</html>

View File

@@ -0,0 +1,239 @@
/**
* ESERCIZIO: Gestore Spese con localStorage
*
* OBIETTIVO:
* Creare un'app che permette all'utente di aggiungere spese, salvarle in localStorage,
* visualizzarle per categoria e calcolare statistiche.
*
* STRUTTURA DATI:
* Array di oggetti spese:
* [
* { id: 1, categoria: "Cibo", importo: 25.50, descrizione: "Cena", data: "2026-02-06" },
* { id: 2, categoria: "Trasporti", importo: 5.00, descrizione: "Benzina", data: "2026-02-06" }
* ]
*/
// SELEZIONE ELEMENTI DOM
const selectCategoria = document.querySelector('#categoria');
const inputImporto = document.querySelector('#importo');
const inputDescrizione = document.querySelector('#descrizione');
const btnAggiungi = document.querySelector('#btnAggiungi');
const btnRipristina = document.querySelector('#btnRipristina');
const btnEsporta = document.querySelector('#btnEsporta');
// STATO DELL'APP con alcuni esempi iniziali (per testare, da rimuovere o modificare in seguito)
let spese = [
{ id: 1, categoria: "Cibo", importo: 25.50, descrizione: "Cena", data: "2026-02-06" },
{ id: 2, categoria: "Trasporti", importo: 5.00, descrizione: "Benzina", data: "2026-02-06" },
{ id: 3, categoria: "Cibo", importo: 15.00, descrizione: "Pranzo", data: "2026-02-05" }
];
let ultimoId = 0;
/**
* FUNZIONE 1: Carica le spese dal localStorage
*
* Passi:
* 1. Controlla se esiste la chiave "spese" in localStorage
* 2. Se esiste, parsa il JSON e assegna a 'spese'
* 3. Se esiste, trova il massimo ID per continuare da lì con ultimoId
* 4. Se non esiste, lascia spese come array vuoto
* 5. Chiama visualizzaLista() per mostrare i dati
*/
function caricaSpeseStorage() {
}
/**
* FUNZIONE 2: Salva tutte le spese nel localStorage
*
* Passi:
* 1. Converti l'array 'spese' in JSON con JSON.stringify()
* 2. Salva la stringa JSON in localStorage con chiave "spese"
*/
function salvaSpeseStorage() {
}
/**
* FUNZIONE 3: Aggiungi una nuova spesa
*
* Passi:
* 1. Leggi i valori dagli input (categoria, importo, descrizione)
* 2. Valida che categoria sia selezionata e importo > 0
* 3. Se non valido, mostra un alert e fermati
* 4. Crea un oggetto spesa con:
* - id: incrementa ultimoId e usa il nuovo valore
* - categoria: il valore selezionato
* - importo: converti a numero float
* - descrizione: il valore dell'input
* - data: la data odierna in formato "YYYY-MM-DD" (usa new Date())
* 5. Aggiungi l'oggetto all'array 'spese'
* 6. Salva con salvaSpeseStorage()
* 7. Svuota gli input
* 8. Chiama visualizzaLista() per aggiornare l'UI
*/
function aggiungiSpesa() {
}
/**
* FUNZIONE 4: Elimina una spesa per indice
*
* Passi:
* 1. Rimuovi l'elemento dall'array 'spese' usando splice(indice, 1)
* 2. Salva con salvaSpeseStorage()
* 3. Chiama visualizzaLista() per aggiornare l'UI
*/
function eliminaSpesa(indice) {
}
/**
* FUNZIONE 5: Calcola le statistiche
*
* Passi:
* 1. Calcola il totale sommando tutti gli importi
* 2. Conta il numero di spese
* 3. Calcola la media: totale / numerospese (se numero > 0, altrimenti 0)
* 4. Ritorna un oggetto con { totale, numero, media }
*/
function calcolaStatistiche() {
let totale = 0;
let numero = 0;
let media = 0;
// TODO: Calcoli qui
return {
totale: totale,
numero: numero,
media: media
};
}
/**
* FUNZIONE 6: Raggruppa spese per categoria
*
* Passi:
* 1. Crea un oggetto vuoto: { }
* 2. Per ogni spesa nell'array, aggiungi la categoria come chiave
* 3. Se la categoria non esiste ancora, crea un array vuoto
* 4. Aggiungi la spesa all'array della categoria
* 5. Ritorna l'oggetto raggruppato
*
* Risultato atteso:
* {
* "Cibo": [spesa1, spesa2],
* "Trasporti": [spesa3],
* ...
* }
*/
function raggruppaSpesePerCategoria() {
let categorie = {};
spese.forEach(spesa => {
if (!categorie[spesa.categoria]) {
categorie[spesa.categoria] = [];
}
categorie[spesa.categoria].push(spesa);
});
return categorie;
}
/**
* FUNZIONE 7: Visualizza e aggiorna tutta l'interfaccia
*
* Passi:
* 1. Chiama calcolaStatistiche() e salva il risultato
* 2. Aggiorna i valori HTML:
* - '#totaleSpese' con il totale formattato (2 decimali)
* - '#numeroSpese' con il numero di spese
* - '#mediaSpesa' con la media formattata (2 decimali)
* 3. Chiama raggruppaSpesePerCategoria() per ottenere le categorie
* 4. Pulisci il contenuto di '#categorieStime'
* 5. Per ogni categoria raggruppata:
* - Crea un div con classe 'categoria-card'
* - Aggiungi un header con il nome categoria e totale
* - Aggiungi una lista (<ul>) con classe 'spese-list'
* - Per ogni spesa della categoria, crea un <li> con classe 'spesa-item'
* con: descrizione, importo, data e pulsante elimina
* - Il pulsante elimina deve chiamare eliminaSpesa(indice) al click
* 6. Se non ci sono spese, mostra un messaggio "Nessuna spesa"
*
* NOTA: Usa toFixed(2) per formattare i numeri a 2 decimali
*/
function visualizzaLista() {
let stats = calcolaStatistiche();
document.querySelector('#totaleSpese').textContent = stats.totale.toFixed(2) + " €";
document.querySelector('#numeroSpese').textContent = stats.numero;
document.querySelector('#mediaSpesa').textContent = stats.media.toFixed(2) + " €";
let categorie = raggruppaSpesePerCategoria();
let containerCategorie = document.querySelector('#categorieStime');
containerCategorie.innerHTML = '';
if (spese.length === 0) {
containerCategorie.innerHTML = '<p>Nessuna spesa aggiunta.</p>';
return;
}
for (let categoria in categorie) {
let divCategoria = document.createElement('div');
divCategoria.classList.add('categoria-card');
let header = document.createElement('h3');
let totaleCategoria = categorie[categoria].reduce((sum, spesa) => sum + spesa.importo, 0);
header.textContent = `${categoria} - Totale: ${totaleCategoria.toFixed(2)}`;
divCategoria.appendChild(header);
let ulSpese = document.createElement('ul');
ulSpese.classList.add('spese-list');
categorie[categoria].forEach(spesa => {
let liSpesa = document.createElement('li');
liSpesa.classList.add('spesa-item');
liSpesa.innerHTML = `
<span>${spesa.descrizione} - ${spesa.importo.toFixed(2)} € - ${spesa.data}</span>
<button class="btn-elimina" onclick="eliminaSpesa(${spese.indexOf(spesa)})">Elimina</button>
`;
ulSpese.appendChild(liSpesa);
});
divCategoria.appendChild(ulSpese);
containerCategorie.appendChild(divCategoria);
}
}
/**
* FUNZIONE 8: Ripristina tutto
*
* Passi:
* 1. Chiedi conferma con confirm()
* 2. Se confermato:
* - Svuota l'array spese: spese = []
* - Resetta ultimoId = 0
* - Elimina la chiave "spese" da localStorage
* - Chiama visualizzaLista()
*/
function ripristinaTutto() {
// Si vede solo nel browser e non nel plugin di vscode
if (confirm("Sei sicuro di voler eliminare tutte le spese?")) {
spese = [];
ultimoId = 0;
localStorage.removeItem("spese");
visualizzaLista();
}
}
// ===== EVENT LISTENER =====
document.addEventListener('DOMContentLoaded', () => {
caricaSpeseStorage();
visualizzaLista();
});
btnAggiungi.addEventListener('click', aggiungiSpesa);
btnRipristina.addEventListener('click', ripristinaTutto);

View File

@@ -0,0 +1,167 @@
body {
font-family: sans-serif;
max-width: 600px;
margin: 2rem auto;
padding: 1rem;
}
h1 {
text-align: center;
font-size: 1.8rem;
margin-bottom: 1rem;
}
h2 {
font-size: 1.1rem;
margin-top: 1.5rem;
margin-bottom: 1rem;
border-bottom: 1px solid #ddd;
padding-bottom: 0.5rem;
}
/* INPUT GROUP */
.input-group {
background: #eee;
padding: 1rem;
border-radius: 8px;
display: flex;
gap: 10px;
margin-bottom: 1rem;
flex-wrap: wrap;
}
input,
select {
padding: 8px;
flex: 1;
min-width: 100px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 8px 16px;
cursor: pointer;
background: #28a745;
color: white;
border: none;
border-radius: 4px;
font-weight: bold;
}
button:hover {
background: #218838;
}
/* STATISTICHE */
.stats-box {
display: flex;
gap: 1rem;
margin-bottom: 1.5rem;
justify-content: space-around;
}
.stat {
background: #f0f0f0;
padding: 1rem;
border-radius: 8px;
flex: 1;
text-align: center;
}
.stat-label {
display: block;
font-size: 0.9rem;
color: #666;
margin-bottom: 0.5rem;
}
.stat-value {
display: block;
font-size: 1.3rem;
font-weight: bold;
color: #28a745;
}
/* CATEGORIE */
.categoria-card {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 0.8rem;
margin-bottom: 1rem;
}
.categoria-card h3 {
margin: 0 0 0.6rem 0;
font-size: 0.95rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid #eee;
}
.spese-list {
list-style: none;
padding: 0;
margin: 0;
font-size: 0.9rem;
}
.spesa-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.4rem;
border-bottom: 1px solid #f0f0f0;
gap: 0.5rem;
}
.spesa-item:last-child {
border-bottom: none;
}
.spesa-item span {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.btn-elimina {
padding: 3px 6px;
background: #dc3545;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 0.75rem;
flex-shrink: 0;
}
.btn-elimina:hover {
background: #c82333;
}
.nessuna-spesa {
text-align: center;
color: #999;
padding: 1.5rem;
font-size: 0.95rem;
}
/* BUTTON GROUP */
.button-group {
display: flex;
gap: 10px;
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid #ddd;
}
.btn-delete {
background: #dc3545;
flex: 1;
}
.btn-delete:hover {
background: #c82333;
}

View File

@@ -20,8 +20,15 @@ const inputAnno = document.querySelector('#anno');
const listaFilm = document.querySelector('#lista-film');
const btnAdd = document.querySelector('#btn-add');
// STATO DELL'APP
let filmWatchlist = [];
// STATO DELL'APP con alcuni esempi iniziali (per testare, da rimuovere o modificare in seguito)
let filmWatchlist = [
{ titolo: "Dune", anno: "2021" },
{ titolo: "Inception", anno: "2010" },
{ titolo: "Matrix", anno: "1999" },
{ titolo: "Interstellar", anno: "2014" },
{ titolo: "Il Signore degli Anelli: La Compagnia dell'Anello", anno: "2001" },
{ titolo: "Harry Potter e la Pietra Filosofale", anno: "2001" }
];
/**
* STEP 1: Funzione Renderizza (visualizza) la lista
@@ -31,7 +38,6 @@ let filmWatchlist = [];
* 3. Aggiungi l'<li> a 'listaFilm'.
*/
function visualizzaLista() {
// TODO: Scrivi qui il codice per visualizzare la lista...
}
/**
@@ -42,7 +48,6 @@ function visualizzaLista() {
* Infine chiama visualizzaLista().
*/
function inizializzaApp() {
// TODO: Scrivi qui il codice per caricare i dati...
}
/**
@@ -55,7 +60,7 @@ function inizializzaApp() {
* 5. Salva l'intero array aggiornato nel localStorage (JSON.stringify!).
* 6. Chiama visualizzaLista().
*/
// TODO: Scrivi qui il codice per aggiungere un film...