{{-- ===================================================== Etebarit - by Gisoo Web Solutions ------------------------------------------------------ Gisoo.net ------------------------------------------------------ Copyright (c) 2026 Gisoo Web Solutions ===================================================== This code is protected by copyright ===================================================== File: dashboard.blade.php ------------------------------------------------------ Use: The admin landing dashboard: headline counters, the twelve-month transaction trend, the payment mix, the central wallet, the pending-work queue (shortcuts) and a recent-activity feed. Follows the approved admin dashboard design export. ===================================================== --}} @extends('layouts.admin') @section('title', __('admin.dashboard.title')) @section('breadcrumb') @endsection @php use App\Support\Format; // Compact money: billions / millions / plain Toman, in Persian digits. $compact = static function (int $v): string { if ($v >= 1_000_000_000) { return Format::persianDigits(rtrim(rtrim(number_format($v / 1_000_000_000, 1, '.', ''), '0'), '.')).' '.__('admin.dashboard.units.billion'); } if ($v >= 1_000_000) { return Format::persianDigits(rtrim(rtrim(number_format($v / 1_000_000, 1, '.', ''), '0'), '.')).' '.__('admin.dashboard.units.million'); } return Format::persianDigits(Format::tomanFa($v)); }; $kpiMeta = [ 'users' => ['money' => false, 'badge' => 'badge_new', 'tone' => 'up', 'accent' => 'primary', 'url' => route('admin.users.index'), 'icon' => ''], 'volume' => ['money' => true, 'badge' => 'badge_orders', 'tone' => 'neutral', 'accent' => 'primary', 'url' => route('admin.orders.index'), 'icon' => ''], 'pending_requests' => ['money' => false, 'badge' => 'badge_queued', 'tone' => 'alert', 'accent' => 'secondary', 'url' => route('admin.requests.index'), 'icon' => ''], 'shops' => ['money' => false, 'badge' => 'badge_new', 'tone' => 'up', 'accent' => 'primary', 'url' => route('admin.shops.index'), 'icon' => ''], ]; $activityIcons = [ 'user' => '', 'request' => '', 'shop' => '', 'withdraw' => '', ]; $toneClasses = [ 'green' => 'bg-[#e7f7ee] text-green-600', 'purple' => 'bg-[#efeafb] text-primary-600', 'amber' => 'bg-[#fff5e6] text-amber-600', ]; $queueIcons = [ 'requests' => '', 'verifications' => '', 'shop_applications' => '', 'gateways' => '', 'withdrawals' => '', 'settlements' => '', 'bank_accounts' => '', ]; @endphp @section('page')

{{ __('admin.dashboard.heading') }}

{{ __('admin.dashboard.info') }} {{-- ===== KPI row ===== --}} {{-- ===== Good-standing distribution ===== --}} @php $stTiers = array_reverse(\App\Support\GoodStanding::tiers()); $stTotal = (int) $standing['total']; $stAvgLevel = \App\Support\GoodStanding::levelForScore($standing['average']); @endphp
{{ __('admin.dashboard.standing.title') }}
{{ __('admin.dashboard.standing.subtitle', ['count' => \App\Support\Format::persianDigits((string) $stTotal)]) }}
{{-- Per-level bars --}}
@foreach ($stTiers as $tier) @php $stCount = (int) ($standing['counts'][$tier['index']] ?? 0); $stPct = $stTotal > 0 ? round($stCount / $stTotal * 100) : 0; @endphp
{{ $tier['label'] }}
{{ \App\Support\Format::persianDigits((string) $stCount) }} ({{ \App\Support\Format::persianDigits((string) $stPct) }}٪)
@endforeach
{{-- Average summary --}}
{{ __('admin.dashboard.standing.average') }}
{{ \App\Support\GoodStanding::label($stAvgLevel) }} {{ \App\Support\Format::persianDigits((string) $standing['average']) }} / {{ \App\Support\Format::persianDigits((string) \App\Support\GoodStanding::MAX_SCORE) }}
{{-- ===== Charts (tabbed, Chart.js) ===== --}} @php $units = [ 'billion' => __('admin.dashboard.units.billion'), 'million' => __('admin.dashboard.units.million'), 'toman' => __('admin.toman'), ]; $mixColors = ['installment' => '#563bb1', 'cash' => '#e80e23', 'online' => '#16a34a']; $mixParts = array_map(fn ($p) => ['label' => __('admin.dashboard.mix.'.$p['key']), 'value' => $p['amount'], 'color' => $mixColors[$p['key']]], $data['mix']['parts']); $creditColors = ['pending' => '#d97706', 'approved' => '#563bb1', 'active' => '#16a34a', 'rejected' => '#e80e23', 'expired' => '#78748c']; $creditParts = array_map(fn ($s) => ['label' => __('admin.requests.statuses.'.$s['key']), 'value' => $s['value'], 'color' => $creditColors[$s['key']]], $data['credit_status']); $instColors = ['upcoming' => '#3b6bd8', 'due' => '#d97706', 'overdue' => '#e80e23', 'paid' => '#16a34a']; $instParts = array_map(fn ($s) => ['label' => __('admin.installments.statuses.'.$s['key']), 'value' => $s['value'], 'color' => $instColors[$s['key']]], $data['installment_status']); $instAmts = [ ['label' => __('admin.dashboard.installments.outstanding'), 'value' => $data['installments']['outstanding'], 'color' => '#563bb1'], ['label' => __('admin.dashboard.installments.overdue'), 'value' => $data['installments']['overdue_amount'], 'color' => '#e80e23'], ['label' => __('admin.dashboard.installments.paid'), 'value' => $data['installments']['paid_total'], 'color' => '#16a34a'], ['label' => __('admin.dashboard.installments.penalties'), 'value' => $data['installments']['penalties'], 'color' => '#d97706'], ]; // Compact server-side specs; the JS builder turns each into a branded chart. $labels = fn ($rows) => array_map(fn ($r) => $r['label'], $rows); $vals = fn ($rows, $k) => array_map(fn ($r) => $r[$k], $rows); $sum = fn ($rows, $k) => array_sum($vals($rows, $k)); $trendPts = $data['trend']['points']; $uPts = $data['users_trend']['points']; $trendSpec = ['kind' => 'bar', 'labels' => array_map(fn ($p) => $p['label'], $trendPts), 'values' => array_map(fn ($p) => $p['amount'], $trendPts), 'color' => '#563bb1', 'money' => true, 'units' => $units]; $mixSpec = ['kind' => 'doughnut', 'labels' => $labels($mixParts), 'values' => $vals($mixParts, 'value'), 'colors' => $vals($mixParts, 'color'), 'money' => true, 'units' => $units, 'center' => $compact($data['mix']['total']), 'centersub' => __('admin.toman')]; $usersSpec = ['kind' => 'line', 'labels' => array_map(fn ($p) => $p['label'], $uPts), 'values' => array_map(fn ($p) => $p['value'], $uPts), 'color' => '#563bb1', 'money' => false]; $creditSpec = ['kind' => 'doughnut', 'labels' => $labels($creditParts), 'values' => $vals($creditParts, 'value'), 'colors' => $vals($creditParts, 'color'), 'money' => false, 'centersub' => __('admin.dashboard.charts.requests_word')]; $instSpec = ['kind' => 'doughnut', 'labels' => $labels($instParts), 'values' => $vals($instParts, 'value'), 'colors' => $vals($instParts, 'color'), 'money' => false, 'centersub' => __('admin.dashboard.charts.installments_word')]; $instAmtSpec = ['kind' => 'hbar', 'labels' => $labels($instAmts), 'values' => $vals($instAmts, 'value'), 'colors' => $vals($instAmts, 'color'), 'money' => true, 'units' => $units]; $trendTotal = array_sum(array_map(fn ($p) => $p['amount'], $trendPts)); $usersTotal = array_sum(array_map(fn ($p) => $p['value'], $uPts)); $creditTotal = $sum($creditParts, 'value'); $instTotal = $sum($instParts, 'value'); $instAmtTotal = $sum($instAmts, 'value'); @endphp
@foreach (['transactions', 'users', 'installments'] as $t) @endforeach
{{-- Tab: transactions --}}

{{ __('admin.dashboard.trend.title') }}

{{ __('admin.dashboard.trend.subtitle') }}
@if ($trendTotal === 0)

{{ __('admin.dashboard.trend.empty') }}

@else
@endif

{{ __('admin.dashboard.mix.title') }}

@if ($data['mix']['total'] === 0)

{{ __('admin.dashboard.mix.empty') }}

@else
@endif
{{-- Tab: users + credit --}}

{{ __('admin.dashboard.charts.users_trend') }}

{{ __('admin.dashboard.charts.users_trend_sub') }}
@if ($usersTotal === 0)

{{ __('admin.dashboard.charts.no_users') }}

@else
@endif

{{ __('admin.dashboard.charts.credit_status') }}

@if ($creditTotal === 0)

{{ __('admin.dashboard.charts.no_credit') }}

@else
@endif
{{-- Tab: installments --}}

{{ __('admin.dashboard.charts.installment_status') }}

@if ($instTotal === 0)

{{ __('admin.dashboard.charts.no_installments') }}

@else
@endif

{{ __('admin.dashboard.charts.installment_amounts') }}

@if ($instAmtTotal === 0)

{{ __('admin.dashboard.charts.no_installments') }}

@else
@endif
{{-- ===== Central wallet + revenue ===== --}} @php $c = $data['central']; $centralNet = $c['central_balance'] - ($c['shops_owed'] + $c['users_cash'] + $c['users_installment'] + $c['pending_withdrawals'] + $c['pending_settlements']); @endphp @if ($centralNet < 0)

{{ __('admin.central.negative_warning') }}

@endif {{-- ===== Installment book ===== --}}

{{ __('admin.dashboard.installments.title') }}

{{-- ===== Installment flows through the central wallet ===== --}}

{{ __('admin.dashboard.flows.title') }}

{{-- ===== What the system owes outward ===== --}}

{{ __('admin.dashboard.liabilities.title') }}

{{ __('admin.dashboard.liabilities.subtitle') }}

{{-- ===== Counts ===== --}}

{{ __('admin.dashboard.counts.title') }}

@php $countLinks = [ 'users' => route('admin.users.index'), 'shops' => route('admin.shops.index'), 'active_credits' => route('admin.requests.index'), 'overdue_installments' => route('admin.installments.index', ['status' => 'overdue']), 'pending_withdrawals' => route('admin.withdrawals.index'), ]; @endphp @foreach (['users', 'shops', 'active_credits', 'overdue_installments', 'pending_withdrawals'] as $key) $key === 'overdue_installments' && $data['central']['counts'][$key] > 0, 'border-line' => ! ($key === 'overdue_installments' && $data['central']['counts'][$key] > 0), ])>
$key === 'overdue_installments' && $data['central']['counts'][$key] > 0, 'text-ink' => ! ($key === 'overdue_installments' && $data['central']['counts'][$key] > 0), ])>@fa($data['central']['counts'][$key])
{{ __("admin.dashboard.counts.{$key}") }}
@endforeach
{{-- ===== Queue (shortcuts) + recent activity ===== --}}
{{-- Pending-work queue: each row jumps straight to the page that clears it --}}

{{ __('admin.dashboard.queue.title') }}

@forelse ($data['queue'] as $row) ! $loop->first])> {!! $queueIcons[$row['key']] !!}
{{ __('admin.dashboard.queue.'.$row['key']) }}
@fa($row['count']) {{ __('admin.dashboard.queue.review') }}
@empty

{{ __('admin.dashboard.queue.empty') }}

@endforelse
{{-- Recent activity feed --}}

{{ __('admin.dashboard.activity.title') }}

@forelse ($data['activity'] as $item)
! $loop->first])> {!! $activityIcons[$item['icon']] !!}
{{ $item['title'] }}
{{ $item['subtitle'] }}
@jalali($item['at'])
@empty

{{ __('admin.dashboard.activity.empty') }}

@endforelse
@endsection