diff --git a/frontend/src/pages/DepotsRetraits.jsx b/frontend/src/pages/DepotsRetraits.jsx index f50ec49..c9477c0 100644 --- a/frontend/src/pages/DepotsRetraits.jsx +++ b/frontend/src/pages/DepotsRetraits.jsx @@ -196,18 +196,27 @@ export default function DepotsRetraits() { // Snapshots "fin d'année" du solde porte-monnaie, calculés côté backend // (GET /dashboard?asOf=YYYY-12-31) : année sélectionnée (si filtre actif) + // année précédente (toujours nécessaire pour le TrendBadge). - useEffect(() => { + // Extrait en fonction nommée pour pouvoir aussi être rappelée après chaque + // mutation (remboursement, mouvement, correction) affectant le porte-monnaie — + // `load()` seul ne suffit pas, ces snapshots vivent dans un state à part. + const loadDashDataAsOf = async () => { if (!activeId && activeView !== 'all') return; const scopeParams = activeView === 'all' ? { scope: 'all' } : undefined; const prevYear = String(Number(drPlatYear || new Date().getFullYear()) - 1); const dates = new Set([`${prevYear}-12-31`]); if (drPlatYear) dates.add(`${drPlatYear}-12-31`); - Promise.all([...dates].map(asOf => - api.get('/dashboard', { ...scopeParams, asOf }).then(d => [asOf, d]) - )).then(entries => { + try { + const entries = await Promise.all([...dates].map(asOf => + api.get('/dashboard', { ...scopeParams, asOf }).then(d => [asOf, d]) + )); setDashDataAsOf(prev => ({ ...prev, ...Object.fromEntries(entries) })); - }).catch(e => console.error('dashDataAsOf load error:', e)); - }, [drPlatYear, activeView, activeId]); // eslint-disable-line + } catch (e) { console.error('dashDataAsOf load error:', e); } + }; + + useEffect(() => { + loadDashDataAsOf(); + // eslint-disable-next-line + }, [drPlatYear, activeView, activeId]); // Ferme tous les menus contextuels au scroll useEffect(() => { @@ -741,7 +750,7 @@ export default function DepotsRetraits() { }; if (editingId) { await api.put(`/depots-retraits/${editingId}`, payload); - close(); await load(); + close(); await Promise.all([load(), loadDashDataAsOf()]); return; } @@ -772,7 +781,7 @@ export default function DepotsRetraits() { investisseurId: Number(form.investisseur_id) || null, }); } else { - await load(); + await Promise.all([load(), loadDashDataAsOf()]); } } catch (e) { setErr(e.message); } }; @@ -794,7 +803,7 @@ export default function DepotsRetraits() { } } setCorrModal(m => ({ ...m, open: false })); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); }; const openRowMenu = (e, row) => { @@ -810,7 +819,7 @@ export default function DepotsRetraits() { await api.del(`/depots-retraits/${rowId}`); setDeleteConfirm(null); setSelectedRow(null); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); }, }); }; @@ -822,7 +831,7 @@ export default function DepotsRetraits() { await api.del(`/corrections/${corrId}`); setDeleteConfirm(null); setSelectedRow(null); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); }, }); }; @@ -834,7 +843,7 @@ export default function DepotsRetraits() { onConfirm: async () => { await api.del(`/depots-retraits/${editingId}`); setDeleteConfirm(null); - close(); setSelectedRow(null); await load(); + close(); setSelectedRow(null); await Promise.all([load(), loadDashDataAsOf()]); }, }); }; diff --git a/frontend/src/pages/Plateformes.jsx b/frontend/src/pages/Plateformes.jsx index 0d8e1a7..37e9fd5 100644 --- a/frontend/src/pages/Plateformes.jsx +++ b/frontend/src/pages/Plateformes.jsx @@ -395,18 +395,27 @@ export default function Plateformes() { // Snapshots backend du solde porte-monnaie : 'live' (aucune coupure) + l'année // sélectionnée (si filtre actif) + l'année précédente (toujours nécessaire pour // le TrendBadge). Même endpoint que DepotsRetraits.jsx (GET /dashboard[?asOf=]). - useEffect(() => { + // Extrait en fonction nommée pour pouvoir aussi être rappelée après chaque + // mutation (remboursement, mouvement, correction) affectant le porte-monnaie — + // `load()` seul ne suffit pas, ces snapshots vivent dans un state à part. + const loadDashDataAsOf = async () => { if (!activeId && activeView !== 'all') return; const scopeParams = activeView === 'all' ? { scope: 'all' } : undefined; const prevYear = selectedYear ? Number(selectedYear) - 1 : new Date().getFullYear() - 1; const keys = new Set(['live', `${prevYear}-12-31`]); if (selectedYear) keys.add(`${selectedYear}-12-31`); - Promise.all([...keys].map(k => - api.get('/dashboard', { ...scopeParams, ...(k === 'live' ? {} : { asOf: k }) }).then(d => [k, d]) - )).then(entries => { + try { + const entries = await Promise.all([...keys].map(k => + api.get('/dashboard', { ...scopeParams, ...(k === 'live' ? {} : { asOf: k }) }).then(d => [k, d]) + )); setDashDataAsOf(prev => ({ ...prev, ...Object.fromEntries(entries) })); - }).catch(e => console.error('dashDataAsOf load error (Plateformes):', e)); - }, [selectedYear, activeView, activeId]); // eslint-disable-line + } catch (e) { console.error('dashDataAsOf load error (Plateformes):', e); } + }; + + useEffect(() => { + loadDashDataAsOf(); + // eslint-disable-next-line + }, [selectedYear, activeView, activeId]); /* ── Section "Mois en cours" (DrillCellPanel) — saisie/édition de remboursements ── */ const [drillRefreshKey, setDrillRefreshKey] = useState(0); @@ -550,7 +559,7 @@ export default function Plateformes() { if (rembEditingId) await api.put(`/remboursements/${rembEditingId}`, payload); else await api.post('/remboursements', payload); closeRembModal(); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); } catch (e) { setRembErr(e.message); } }; @@ -558,7 +567,7 @@ export default function Plateformes() { try { await api.del(`/remboursements/${rembEditingId}`); closeRembModal(); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); } catch (e) { setRembErr(e.message); } }; @@ -1289,13 +1298,13 @@ export default function Plateformes() { }; if (mvEditingId) { await api.put(`/depots-retraits/${mvEditingId}`, payload); - mvCloseEdit(); await load(); + mvCloseEdit(); await Promise.all([load(), loadDashDataAsOf()]); return; } // Pas de création depuis cet onglet — le bouton global "+ Nouveau dépôt/retrait" // (topbar) couvre déjà ce besoin et redirige vers /depots-retraits. await api.post('/depots-retraits', payload); - mvCloseEdit(); await load(); + mvCloseEdit(); await Promise.all([load(), loadDashDataAsOf()]); } catch (e) { setMvErr(e.message); } }; @@ -1316,7 +1325,7 @@ export default function Plateformes() { } } setMvCorrModal(m => ({ ...m, open: false })); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); }; const mvOpenRowMenu = (e, row) => { @@ -1332,7 +1341,7 @@ export default function Plateformes() { await api.del(`/depots-retraits/${rowId}`); setMvDeleteConfirm(null); setMvSelectedRow(null); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); }, }); }; @@ -1344,7 +1353,7 @@ export default function Plateformes() { await api.del(`/corrections/${corrId}`); setMvDeleteConfirm(null); setMvSelectedRow(null); - await load(); + await Promise.all([load(), loadDashDataAsOf()]); }, }); }; @@ -1356,7 +1365,7 @@ export default function Plateformes() { onConfirm: async () => { await api.del(`/depots-retraits/${mvEditingId}`); setMvDeleteConfirm(null); - mvCloseEdit(); setMvSelectedRow(null); await load(); + mvCloseEdit(); setMvSelectedRow(null); await Promise.all([load(), loadDashDataAsOf()]); }, }); }; @@ -2026,7 +2035,7 @@ export default function Plateformes() { refreshKey={drillRefreshKey} investissements={platRows} plateformes={plats.filter(p => filteredPlatIds.has(p.id))} - onBulkDone={load} + onBulkDone={() => Promise.all([load(), loadDashDataAsOf()])} />