@php $carbonLocale = \App\Support\AppLocale::carbon(); $tx = $finance->transactions(); $budgets = $finance->budgets(); $goals = $finance->goals(); $subs = $finance->subscriptions(); $debts = $finance->debts(); $totalBalance = collect($tx)->sum('amount'); $monthIncome = collect($tx)->where('type', 'income')->sum('amount'); $monthExpenses = collect($tx)->where('type', 'expense')->sum(fn ($t) => abs($t['amount'])); $totalFlow = $monthIncome + $monthExpenses; $incomeShare = $totalFlow > 0 ? ($monthIncome / $totalFlow) * 100 : 0; $net = $monthIncome - $monthExpenses; $savingsRate = $monthIncome > 0 ? ($net / $monthIncome) * 100 : 0; $daysLeft = 14; $safeAmount = collect($budgets)->sum(fn ($b) => max(($b['limit'] ?? 0) - ($b['spent'] ?? 0), 0)); $daily = $daysLeft > 0 ? $safeAmount / $daysLeft : 0; $emergency = collect($goals)->first(fn ($g) => str_contains(strtolower($g['name']), 'emergency')); $emergencyPct = $emergency && ($emergency['target'] ?? 0) > 0 ? (($emergency['saved'] ?? 0) / $emergency['target']) * 100 : 0; $txForRecent = array_values(array_filter($tx, static function (array $row): bool { return ! \App\Support\RelativeDayLabel::isFutureTransactionDate((string) ($row['date'] ?? '')); })); $txRecentGrouped = \App\Support\RelativeDayLabel::groupedTransactionSections(collect($txForRecent)->take(6)->values()->all(), $carbonLocale); $hasFinanceData = count($tx) > 0 || count($budgets) > 0 || count($goals) > 0 || count($subs) > 0 || count($debts) > 0; $aiDashboardTips = \App\Support\FinanceDataInsights::dashboardTips($tx, $budgets, $subs, $debts, $goals); @endphp
@if ($showPushPrompt)

{{ __('notifications.types.system_push_prompt_title') }}

{{ __('notifications.types.system_push_prompt_message') }}

@endif
@if ($this->editing)
{{ __('budgets.dashboard_page.layout_hint_editing') }}
{{ __('budgets.dashboard_page.layout_hint_sizes') }}
@elseif (count($this->hidden) > 0) {{ count($this->hidden) === 1 ? __('budgets.dashboard_page.widgets_hidden_one', ['count' => count($this->hidden)]) : __('budgets.dashboard_page.widgets_hidden_other', ['count' => count($this->hidden)]) }} @else {{ __('budgets.dashboard_page.layout_saved') }} @endif
@if ($this->editing) @endif
@if (count($visibleWidgets) > 0 && ! $hasFinanceData)

{{ __('budgets.dashboard_page.empty_finance_title') }}

{{ __('budgets.dashboard_page.empty_finance_body') }}

@endif @if (count($visibleWidgets) > 0)
@foreach ($visibleWidgets as $id) @php $size = $this->sizeFor($id); $cell = $this->cellClass($id); $isHidden = in_array($id, $this->hidden, true); $widgetDelay = match ($id) { 'balance' => 0.05, 'income-expense' => 0.10, 'safe-to-spend' => 0.15, 'upcoming' => 0.20, 'recent-transactions' => 0.22, 'budgets' => 0.25, 'goals' => 0.30, 'subscriptions' => 0.35, 'debts' => 0.40, 'ai' => 0.45, default => 0.05, }; @endphp
editing) draggable="true" x-on:dragstart="draggingId = @js($id); overId = null; event.dataTransfer?.setData('text/plain', @js($id)); event.dataTransfer?.setDragImage(event.currentTarget, 20, 20); $wire.dragStart(@js($id))" x-on:dragover.prevent="if (draggingId && draggingId !== @js($id)) { overId = @js($id) }" x-on:drop.prevent.stop="if (draggingId && draggingId !== @js($id)) { $wire.dropByIds(draggingId, @js($id)) }; draggingId = null; overId = null" x-on:dragend="draggingId = null; overId = null; $wire.dragEnd()" @endif class="relative flex min-h-0 flex-col transition-[opacity,transform,box-shadow] {{ $cell }} {{ $this->editing ? 'cursor-grab active:cursor-grabbing' : '' }} {{ $isHidden ? 'opacity-50' : '' }}" x-bind:class="{ 'scale-[0.99] opacity-40': draggingId === @js($id), 'z-10 rounded-[18px] ring-2 ring-primary/55 ring-offset-2 ring-offset-background': overId === @js($id) }" > @if ($this->editing)
{{ __('budgets.dashboard_page.widget_labels.' . $id) }}
@endif
@include('livewire.partials.dashboard-widget-body', [ 'id' => $id, 'tx' => $tx, 'txRecentGrouped' => $txRecentGrouped, 'budgets' => $budgets, 'goals' => $goals, 'subs' => $subs, 'debts' => $debts, 'locale' => $carbonLocale, 'totalBalance' => $totalBalance, 'monthIncome' => $monthIncome, 'monthExpenses' => $monthExpenses, 'incomeShare' => $incomeShare, 'net' => $net, 'savingsRate' => $savingsRate, 'daysLeft' => $daysLeft, 'safeAmount' => $safeAmount, 'daily' => $daily, 'emergency' => $emergency, 'emergencyPct' => $emergencyPct, 'delay' => $widgetDelay, 'aiTips' => $aiDashboardTips, ])
@endforeach
@else

{{ __('budgets.dashboard_page.empty_widgets_title') }}

{{ __('budgets.dashboard_page.empty_widgets_body') }}

@endif