Add budget progress gauge inside mobile category buttons
Each depense/epargne category button on the mobile quick-entry form now shows a fill bar plus percentage of its monthly budget already tracked, so the user sees at a glance which categories are close to their limit while picking one. Categories without a budget defined in Plan show no gauge (avoids a misleading 0%). Capped at 100% — overspend detail already lives on the dashboard's "Manque" column. 3 new Pest tests for the percentage calculation (normal, capped, no-budget cases). 61/61 tests pass, Pint clean, verified on mobile against production data. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5861fc49fc
commit
613220f43a
@@ -6,6 +6,7 @@ namespace App\Livewire\Suivi;
|
||||
|
||||
use App\Enums\CategoryType;
|
||||
use App\Models\BudgetLine;
|
||||
use App\Models\Category;
|
||||
use App\Models\RecurringTransaction;
|
||||
use App\Models\Transaction;
|
||||
use Livewire\Attributes\Layout;
|
||||
@@ -108,6 +109,32 @@ class Index extends Component
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Budget planifié pour cette catégorie sur le mois en cours, en résolvant
|
||||
* l'override du mois s'il existe sinon le montant par défaut de l'année.
|
||||
*/
|
||||
private function budgetForCurrentMonth(Category $category, int $year, int $month): ?float
|
||||
{
|
||||
$lines = $category->budgetLines()->where('year', $year)->get();
|
||||
|
||||
$override = $lines->firstWhere('month', $month);
|
||||
if ($override) {
|
||||
return (float) $override->amount;
|
||||
}
|
||||
|
||||
$default = $lines->firstWhere('month', null);
|
||||
|
||||
return $default ? (float) $default->amount : null;
|
||||
}
|
||||
|
||||
private function trackedForCategoryThisMonth(Category $category, int $year, int $month): float
|
||||
{
|
||||
return (float) $category->transactions()
|
||||
->whereYear('date_effective', $year)
|
||||
->whereMonth('date_effective', $month)
|
||||
->sum('amount');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
$household = auth()->user()->currentHousehold;
|
||||
@@ -159,10 +186,27 @@ class Index extends Component
|
||||
->sortBy('day_of_month')
|
||||
->values();
|
||||
|
||||
$categories = $household->categories()->orderBy('type')->orderBy('position')->get();
|
||||
|
||||
$categoryProgress = $categories
|
||||
->whereIn('type', [CategoryType::Depense, CategoryType::Epargne])
|
||||
->mapWithKeys(function (Category $category) use ($year, $month) {
|
||||
$budget = $this->budgetForCurrentMonth($category, $year, $month);
|
||||
|
||||
if ($budget === null || $budget <= 0) {
|
||||
return [$category->id => null];
|
||||
}
|
||||
|
||||
$tracked = $this->trackedForCategoryThisMonth($category, $year, $month);
|
||||
|
||||
return [$category->id => min(100, round($tracked / $budget * 100))];
|
||||
});
|
||||
|
||||
return view('livewire.suivi.index', [
|
||||
'transactions' => $transactions,
|
||||
'running' => $running,
|
||||
'categories' => $household->categories()->orderBy('type')->orderBy('position')->get(),
|
||||
'categories' => $categories,
|
||||
'categoryProgress' => $categoryProgress,
|
||||
'nbrThisYear' => $transactions->filter(fn (Transaction $t) => $t->date->year === $year)->count(),
|
||||
'nbrTotal' => $transactions->count(),
|
||||
'lastEntry' => $transactions->first(),
|
||||
|
||||
Reference in New Issue
Block a user