Files
suivicpt/resources/views/livewire/plan/index.blade.php
T
jeremy bayseandClaude Sonnet 5 d8dc57a5df Initial commit: SuiviCPT personal finance tracker
Laravel 11 + Livewire 3/Volt + Alpine.js + Tailwind app for household
budget planning, transaction tracking, and financial dashboards.

- Multi-tenant households with member invites
- Plan: monthly/yearly budget per category with overrides
- Suivi: transaction log with running balance (desktop + mobile quick-entry)
- Dashboard: budget vs tracked breakdown + Chart.js donuts
- Flux: Sankey diagram of income allocation
- WCAG 2.1 AA color tokens, dark mode, accessible tables/forms
- 50 Pest tests

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:39:42 +02:00

101 lines
6.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div class="max-w-[1600px] mx-auto py-6 px-4 sm:px-6 space-y-6">
<div class="flex items-center justify-between">
<h1 class="text-xl font-semibold text-text">Plan</h1>
<div class="flex items-center gap-2">
<button wire:click="setYear({{ $year - 1 }})" aria-label="Année précédente" class="px-2 py-1 text-sm rounded-md border border-border-strong text-text focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring">&lsaquo;</button>
<span class="text-sm font-medium text-text-muted w-16 text-center">{{ $year }}</span>
<button wire:click="setYear({{ $year + 1 }})" aria-label="Année suivante" class="px-2 py-1 text-sm rounded-md border border-border-strong text-text focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring">&rsaquo;</button>
</div>
</div>
@php
$colors = [
'revenu' => ['bg' => 'bg-positive-fill', 'row' => 'bg-positive-surface/40'],
'depense' => ['bg' => 'bg-negative-fill', 'row' => 'bg-negative-surface/40'],
'epargne' => ['bg' => 'bg-info-fill', 'row' => 'bg-info-surface/40'],
];
@endphp
@foreach ($types as $type)
@php $section = $sections[$type->value]; @endphp
<div class="bg-surface shadow rounded-lg overflow-hidden">
<div class="{{ $colors[$type->value]['bg'] }} px-4 py-2">
<h2 class="text-white font-semibold">{{ $type->label() }}</h2>
</div>
<div class="p-2">
<table class="w-full table-fixed text-[11px] sm:text-xs border-collapse">
<caption class="sr-only">Budget {{ Str::lower($type->label()) }} par mois pour {{ $year }}</caption>
<colgroup>
<col style="width: 12%">
<col style="width: 6.77%">
@for ($m = 1; $m <= 12; $m++)
<col style="width: 6.77%">
@endfor
</colgroup>
<thead>
<tr class="text-text-muted border-b border-border">
<th scope="col" class="text-left px-1 py-2 truncate">Catégorie</th>
<th scope="col" class="px-0.5 py-2">Défaut</th>
@foreach ($months as $m)
<th scope="col" class="px-0.5 py-2">{{ $m }}</th>
@endforeach
</tr>
</thead>
<tbody>
@forelse ($section['categories'] as $entry)
<tr class="border-b border-border/60">
<th scope="row" class="px-1 py-1 truncate text-text font-normal text-left" title="{{ $entry['category']->name }}">{{ $entry['category']->name }}</th>
<td class="px-0.5 py-1">
<label class="sr-only" for="amount-{{ $entry['category']->id }}-default">Montant par défaut pour {{ $entry['category']->name }}</label>
<input
id="amount-{{ $entry['category']->id }}-default"
type="number" step="0.01"
value="{{ $entry['row']['default'] }}"
wire:change="updateAmount({{ $entry['category']->id }}, null, $event.target.value)"
class="w-full min-w-0 bg-surface text-right text-[11px] sm:text-xs px-1 py-0.5 rounded border-border-strong text-text font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</td>
@for ($m = 1; $m <= 12; $m++)
<td class="px-0.5 py-1">
<label class="sr-only" for="amount-{{ $entry['category']->id }}-{{ $m }}">Montant pour {{ $entry['category']->name }}, {{ $months[$m - 1] }}</label>
<input
id="amount-{{ $entry['category']->id }}-{{ $m }}"
type="number" step="0.01"
value="{{ $entry['row'][$m] }}"
wire:change="updateAmount({{ $entry['category']->id }}, {{ $m }}, $event.target.value)"
class="w-full min-w-0 bg-surface text-right text-[11px] sm:text-xs px-1 py-0.5 rounded border-border-strong text-text focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</td>
@endfor
</tr>
@empty
<tr><td colspan="14" class="px-4 py-3 text-sm text-text-muted">Aucune catégorie. Ajoutez-en dans <a href="{{ route('categories') }}" wire:navigate class="underline text-brand rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring">Catégories</a>.</td></tr>
@endforelse
</tbody>
@if ($section['categories']->isNotEmpty())
<tfoot>
<tr class="font-semibold {{ $colors[$type->value]['row'] }} text-text">
<th scope="row" class="px-1 py-2 truncate font-semibold text-left">Total</th>
<td class="px-0.5 py-2 text-right">{{ number_format($section['totals']['default'], 0, ',', ' ') }} </td>
@for ($m = 1; $m <= 12; $m++)
<td class="px-0.5 py-2 text-right">{{ number_format($section['totals'][$m], 0, ',', ' ') }} </td>
@endfor
</tr>
@if ($type->value === 'revenu')
<tr class="text-[11px] sm:text-xs text-text-muted">
<th scope="row" class="px-1 py-1 truncate font-normal text-left">Reste à affecter</th>
<td class="px-0.5 py-1 text-right"></td>
@for ($m = 1; $m <= 12; $m++)
<td class="px-0.5 py-1 text-right {{ $section['remaining'][$m] < 0 ? 'text-danger font-semibold' : '' }}">{{ $section['remaining'][$m] < 0 ? '' : '+' }}{{ number_format(abs($section['remaining'][$m]), 0, ',', ' ') }} </td>
@endfor
</tr>
@endif
</tfoot>
@endif
</table>
</div>
</div>
@endforeach
</div>