diff --git a/budget.php b/budget.php index 60000d0..6685dd9 100644 --- a/budget.php +++ b/budget.php @@ -51,5 +51,4 @@ require __DIR__ . '/header.php'; ?> - \ No newline at end of file diff --git a/modules/budget/budget.css b/modules/budget/budget.css index 6429c61..70098a5 100644 --- a/modules/budget/budget.css +++ b/modules/budget/budget.css @@ -157,6 +157,7 @@ color: var(--text-muted); border: 1px solid #cbd5e1; box-shadow: none; + margin-bottom: 5px; } .pf-btn.btn-secondary:hover { @@ -415,7 +416,7 @@ input[type="checkbox"]:checked::after { animation: modalPop 0.3s cubic-bezier(0.16, 1, 0.3, 1); display: flex; flex-direction: column; - gap: 16px; + gap: 10px; } @keyframes modalPop { @@ -512,6 +513,7 @@ input[type="checkbox"]:checked::after { .pf-btn { width: 100%; justify-content: center; + margin-top: 5px; } .pf-table { diff --git a/modules/budget/budget.js b/modules/budget/budget.js deleted file mode 100644 index 647dc15..0000000 --- a/modules/budget/budget.js +++ /dev/null @@ -1,213 +0,0 @@ -/** - * Change l'état "payé/attente" d'un frais sans recharger la page - */ -function toggleCheck(id, isChecked) { - const formData = new FormData(); - formData.append("action", "toggle-check"); - formData.append("id", id); - formData.append("status", isChecked ? 1 : 0); - - fetch("/modules/budget/includes/api/manage-item.php", { - method: "POST", - body: formData, - }) - .then((response) => { - if (!response.ok) throw new Error("Erreur réseau"); - // Optionnel : on pourrait actualiser un petit label ici - console.log("Statut mis à jour pour l'item " + id); - }) - .catch((error) => { - alert("Erreur lors de la mise à jour"); - console.error(error); - }); -} - -/** - * Supprime un item après confirmation - */ -function deleteItem(id) { - if (confirm("Voulez-vous vraiment supprimer cet élément ?")) { - const formData = new FormData(); - formData.append("action", "delete"); - formData.append("id", id); - - fetch("/modules/budget/includes/api/manage-item.php", { - method: "POST", - body: formData, - }).then(() => { - window.location.reload(); // On recharge pour mettre à jour les totaux - }); - } -} - -/** - * Ouvre la modal et pré-remplit les champs pour la modification - */ -function editItem(item) { - // Si 'item' arrive sous forme de string JSON depuis l'attribut HTML - const data = typeof item === "string" ? JSON.parse(item) : item; - - document.getElementById("modalTitle").innerText = "Modifier : " + data.name; - document.getElementById("item_id").value = data.id; - document.getElementById("item_name").value = data.name; - document.getElementById("item_amount").value = data.amount; - document.getElementById("item_category").value = data.category; - document.getElementById("item_type").value = data.type; - document.getElementById("item_day").value = data.payment_day; - document.getElementById("item_reg_month").value = data.reg_month || ""; - document.getElementById("item_is_estimate").value = data.is_estimate; - - document.getElementById("budgetModal").style.display = "flex"; -} - -function openModal(mode) { - if (mode === "add") { - document.getElementById("modalTitle").innerText = "Ajouter un élément"; - document.getElementById("item_id").value = ""; - document.querySelector("#budgetModal form").reset(); - } - document.getElementById("budgetModal").style.display = "flex"; -} - -function closeModal() { - document.getElementById("budgetModal").style.display = "none"; -} - -// Variable globale pour stocker les catégories existantes (passées par PHP) -let knownCategories = []; - -function openSavingsModal(mode, owner) { - document.getElementById("savingsModal").style.display = "flex"; - document.getElementById("sav_owner").value = owner; // On stocke le owner dans le form caché - - const container = document.getElementById("linesContainer"); - container.innerHTML = ""; - - if (mode === "add") { - document.getElementById("savingsModalTitle").innerText = - "Nouveau pour " + owner; - document.getElementById("sav_date").valueAsDate = new Date(); - document.getElementById("sav_total").value = ""; - // Par défaut, une ligne vide - createLine("", ""); - } -} - -function editMonth(monthDate, owner, dataValues, allCats) { - document.getElementById("savingsModal").style.display = "flex"; - document.getElementById("savingsModalTitle").innerText = - "Modifier " + owner + " (" + monthDate + ")"; - document.getElementById("sav_owner").value = owner; - document.getElementById("sav_date").value = monthDate; - - knownCategories = allCats || []; - const container = document.getElementById("linesContainer"); - container.innerHTML = ""; - - // Total - if (dataValues["TOTAL_BANQUE"]) { - document.getElementById("sav_total").value = dataValues["TOTAL_BANQUE"]; - delete dataValues["TOTAL_BANQUE"]; - } else { - document.getElementById("sav_total").value = ""; - } - - // Lignes existantes - for (const [category, amount] of Object.entries(dataValues)) { - createLine(category, amount); - } - createLine("", ""); -} - -function addNewLine() { - createLine("", ""); -} - -/** - * Crée une ligne HTML dans la modale : [ Nom de la catégorie ] [ Montant ] [ X ] - */ -function createLine(name, amount) { - const container = document.getElementById("linesContainer"); - const div = document.createElement("div"); - div.className = "savings-line-item"; - const listId = "list_" + Math.random().toString(36).substr(2, 9); - - div.innerHTML = ` -
- - ${knownCategories.map((c) => ` -
- - - `; - container.appendChild(div); -} - -/** - * Supprime une entrée spécifique (Mois + Catégorie) sans recharger la page (si possible) - */ -function deleteSavingsEntry(monthDate, category, owner) { - if (!confirm(`Supprimer le montant pour "${category}" ?`)) return; - - const formData = new FormData(); - formData.append("action", "delete_entry"); - formData.append("month_date", monthDate); - formData.append("category", category); - formData.append("owner", owner); - - fetch("/modules/budget/includes/api/save-savings.php", { - method: "POST", - body: formData, - }).then(() => window.location.reload()); -} - -/** - * Duplique le dernier mois vers le mois suivant - */ -function duplicateLastMonth(lastMonthDate, owner) { - let dateObj = new Date(lastMonthDate); - dateObj.setMonth(dateObj.getMonth() + 1); - let nextMonthStr = dateObj.toISOString().split("T")[0]; - - let newTotal = prompt( - `Dupliquer pour ${owner} vers ${nextMonthStr} ?\n\nNouveau TOTAL :`, - "", - ); - - if (newTotal !== null && newTotal.trim() !== "") { - const formData = new FormData(); - formData.append("action", "duplicate_month"); - formData.append("source_date", lastMonthDate); - formData.append("target_date", nextMonthStr); - formData.append("new_total", newTotal); - formData.append("owner", owner); - - fetch("/modules/budget/includes/api/save-savings.php", { - method: "POST", - body: formData, - }) - .then((r) => r.json()) - .then((d) => { - if (d.success) window.location.reload(); - else alert(d.error); - }); - } -} - -/** - * Supprime toutes les données d'un mois pour le propriétaire actuel - */ -function deleteEntireMonth(monthDate, owner) { - if (!confirm(`Supprimer TOUT le mois de ${monthDate} pour ${owner} ?`)) - return; - - const formData = new FormData(); - formData.append("action", "delete_month_global"); - formData.append("month_date", monthDate); - formData.append("owner", owner); - - fetch("/modules/budget/includes/api/save-savings.php", { - method: "POST", - body: formData, - }).then(() => window.location.reload()); -} diff --git a/modules/budget/includes/api/save-savings.php b/modules/budget/includes/api/save-savings.php index d1cba60..001d7fd 100644 --- a/modules/budget/includes/api/save-savings.php +++ b/modules/budget/includes/api/save-savings.php @@ -6,7 +6,6 @@ require_login(); // --- ACTION : SUPPRESSION D'UNE ENTRÉE UNIQUE --- if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'delete_entry') { $owner = $_POST['owner']; - $redirectTab = $_POST['redirect_tab'] ?? $owner; $date = $_POST['month_date']; $cat = $_POST['category']; @@ -40,7 +39,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'dupli $stmtIns->execute([$owner, $targetDate, 'TOTAL_BANQUE', $newTotal]); // 3. Copier toutes les catégories (sauf TOTAL_BANQUE) du mois source - // On insère directement avec une requête INSERT SELECT $sqlCopy = "INSERT INTO pf_savings (owner, month_date, category, amount) SELECT owner, ?, category, amount FROM pf_savings @@ -76,30 +74,37 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'delet } // --- ACTION : SAUVEGARDE CLASSIQUE (MODALE) --- -// (Le code précédent reste ici pour la sauvegarde via le formulaire classique) if ($_SERVER['REQUEST_METHOD'] === 'POST') { $owner = $_POST['owner']; + + // CORRECTION ICI : On récupère l'onglet de redirection (Nens, Alex ou Laia) + $redirectTab = $_POST['redirect_tab'] ?? $owner; + $dateInput = $_POST['month_date']; $dateObj = new DateTime($dateInput); $monthDate = $dateObj->format('Y-m-01'); - $values = $_POST['values'] ?? []; // Pour la modale standard + $values = $_POST['values'] ?? []; // Tableau généré par nos champs JS: values[Catégorie] - // ... (Garde ton code précédent de sauvegarde ici) ... - // Note : Ajoute ce bloc TRY CATCH si tu ne l'avais pas déjà try { $pdo->beginTransaction(); + + // On supprime d'abord les anciennes données du mois pour cet utilisateur $stmtDel = $pdo->prepare("DELETE FROM pf_savings WHERE owner = ? AND month_date = ?"); $stmtDel->execute([$owner, $monthDate]); + // On réinsère les nouvelles données $stmtIns = $pdo->prepare("INSERT INTO pf_savings (owner, month_date, category, amount) VALUES (?, ?, ?, ?)"); foreach ($values as $category => $amount) { $amount = floatval($amount); + // On enregistre si c'est positif OU si c'est le total banque if ($amount > 0 || $category === 'TOTAL_BANQUE') { $stmtIns->execute([$owner, $monthDate, $category, $amount]); } } $pdo->commit(); - header("Location: /budget.php?tab=epargne&owner=$redirectTab"); + + // Redirection vers le bon onglet + header("Location: /budget.php?tab=epargne&owner=" . urlencode($redirectTab)); exit; } catch (Exception $e) { $pdo->rollBack(); diff --git a/modules/budget/views/epargne.php b/modules/budget/views/epargne.php index 1543802..631ba92 100644 --- a/modules/budget/views/epargne.php +++ b/modules/budget/views/epargne.php @@ -1,4 +1,6 @@ + +
@@ -14,7 +28,7 @@ $ownersToDisplay = ($requestedOwner === 'Nens') ? ['Pol', 'Pep'] : [$requestedOw Laia Nens 👶
-
+ ;">

@@ -56,122 +69,340 @@ $ownersToDisplay = ($requestedOwner === 'Nens') ? ['Pol', 'Pep'] : [$requestedOw 🔁 +1 Mois -

- -
- +
+

Aucune donnée pour .

- - - - - + + + + + + +
Poste / Mois -
- -
- - + + + + + + - - - - - - - - - - + + + + + + + + + + + - - - - - + + + + + + + - - - - - - - - - -
Poste / Mois +
+ +
+ + +
- -
Total - € -
Total + € +
- -
- - - -
- - -
+ +
+ - + +
+ - +
Extra - € -
+
Extra + € +
-
+ +
-
-

Saisir le mois

+
+
+

Saisir le mois

+ +
+ + +
+
+ + +
+ +
+ + +
+
+ +
- - -
- - +
+
+

Ventilation

+ Utilisez l'ajustement (+/-) pour recalculer automatiquement. +
+
-
- - +
+
Catégorie
+
Actuel
+
Ajust (+/-)
+
Nouveau
+
-
- -
-

Ventilation

- -
+
+
-
- - -
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/modules/budget/views/recap.php b/modules/budget/views/recap.php index d36bdc4..3d96bcf 100644 --- a/modules/budget/views/recap.php +++ b/modules/budget/views/recap.php @@ -1,4 +1,6 @@ query("SELECT * FROM pf_budget_items ORDER BY category DESC, sort_order ASC, name ASC"); $items = $stmt->fetchAll(); @@ -8,146 +10,155 @@ $totalRevenusMensuels = 0; ?>
-
-

Récapitulatif Mensuel

- +
+

Récapitulatif Mensuel

+
- - - - - - - - - - - - - - +
NomMontantTypeJourÉtat prélèvementRégularisationActions
+ + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - -
NomMontantTypeJourÉtat prélèvementRégularisationActions
- - (Est.)' : '' ?> - - € - - - - - - - onclick="toggleCheck(, this.checked)" - title="Marquer comme payé"> - Payé' : ' Attente' ?> - - - -
- - -
-
Total Revenus Mensuels+
Total Dépenses Mensuelles-
Équilibre du compte - € / mois -
+ + $rowClass = ($item['category'] === 'income') ? 'row-income' : 'row-expense'; + if ($item['is_estimate']) $rowClass .= ' row-estimate'; + ?> + + + + (Est.)' : '' ?> + + + € + + + + + + + + +
+ + onclick="toggleItemCheck(, this.checked)" + title="Marquer comme payé" + style="width:18px; height:18px; cursor:pointer;"> + Payé' : ' Attente' ?> +
+ + + + + +
+ + +
+ + + + + + + Total Revenus Mensuels + + + + + Total Dépenses Mensuelles + - + + + Équilibre du compte + + + € / mois + + + + +
-
+

* Note : Les frais de type "Annuel" sont affichés pour information mais ne sont pas inclus dans le calcul de l'équilibre mensuel.

-
-
-

Ajouter un élément

+