Implement a comprehensive overhaul of the Filament admin dashboard, introducing a structured 12-column responsive grid layout and enhanced visual identity. Key changes include: - Redesigned Dashboard layout with a 4-layer progressive disclosure architecture (KPIs, Exchange Rates, Data Tables, and Trends). - Introduced custom IFNEX design tokens via CSS, including branded stat cards, status badges, and improved sidebar typography. - Enhanced FinanceOverviewWidget with real-time trend analysis and sparkline-ready data structures. - Refactored RecentShipments and RecentTransactions widgets to use custom Blade templates for a more polished, consistent UI. - Integrated brand assets including the company logo and custom authentication pages. - Added global number formatting helpers and integrated them into financial widgets. - Updated AdminPanelProvider to support custom login pages and brand-specific header/footer hooks.
100 lines
4.2 KiB
PHP
100 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Widgets;
|
|
|
|
use App\Models\ExchangeRateHistory;
|
|
use App\Services\ExchangeRateService;
|
|
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
|
|
use Filament\Widgets\StatsOverviewWidget\Stat;
|
|
|
|
/**
|
|
* Layer 2 (right) — live exchange-rate summary, spanning 4/12 of the body grid.
|
|
*/
|
|
class ExchangeRateWidget extends BaseWidget
|
|
{
|
|
protected static ?int $sort = 3;
|
|
|
|
protected static bool $isLazy = false;
|
|
|
|
protected int|string|array $columnSpan = 12;
|
|
|
|
/**
|
|
* Stat cards inside the rate widget: 1 column on the narrow lg+ column,
|
|
* 2 on mobile so they don't all stack vertically on tiny screens.
|
|
*/
|
|
protected int|string|array $columns = 1;
|
|
|
|
protected function getStats(): array
|
|
{
|
|
$service = app(ExchangeRateService::class);
|
|
|
|
$aedInfo = $service->getLatestRateInfo('AED', 'IRR');
|
|
$usdInfo = $service->getLatestRateInfo('USD', 'IRR');
|
|
|
|
$aedChangePercent = $aedInfo['change_percent'];
|
|
$usdChangePercent = $usdInfo['change_percent'];
|
|
|
|
$aedChart = $service->getRateChart('AED', 'IRR', 7);
|
|
$usdChart = $service->getRateChart('USD', 'IRR', 7);
|
|
|
|
return [
|
|
Stat::make('نرخ درهم (AED)', ifnex_format_number($aedInfo['current_rate'] ?? 0))
|
|
->description(
|
|
$aedChangePercent !== null
|
|
? sprintf('%s %s — %s',
|
|
$aedChangePercent > 0 ? '↑' : ($aedChangePercent < 0 ? '↓' : '—'),
|
|
ifnex_persian_digits(number_format(abs((float) $aedChangePercent), 2)) . '%',
|
|
($aedInfo['changed_by'] ?? 'سیستم'))
|
|
: 'آخرین تغییر: ' . ($aedInfo['last_updated']?->format('Y/m/d H:i') ?? '—')
|
|
)
|
|
->descriptionIcon(
|
|
$aedChangePercent > 0 ? 'heroicon-m-arrow-trending-up' :
|
|
($aedChangePercent < 0 ? 'heroicon-m-arrow-trending-down' : 'heroicon-m-minus')
|
|
)
|
|
->icon('heroicon-o-currency-dollar')
|
|
->color(
|
|
$aedChangePercent > 0 ? 'danger' :
|
|
($aedChangePercent < 0 ? 'success' : 'gray')
|
|
)
|
|
->chart(!empty($aedChart) ? $aedChart : [0]),
|
|
|
|
Stat::make('نرخ دلار (USD)', ifnex_format_number($usdInfo['current_rate'] ?? 0))
|
|
->description(
|
|
$usdChangePercent !== null
|
|
? sprintf('%s %s — %s',
|
|
$usdChangePercent > 0 ? '↑' : ($usdChangePercent < 0 ? '↓' : '—'),
|
|
ifnex_persian_digits(number_format(abs((float) $usdChangePercent), 2)) . '%',
|
|
($usdInfo['changed_by'] ?? 'سیستم'))
|
|
: 'آخرین تغییر: ' . ($usdInfo['last_updated']?->format('Y/m/d H:i') ?? '—')
|
|
)
|
|
->descriptionIcon(
|
|
$usdChangePercent > 0 ? 'heroicon-m-arrow-trending-up' :
|
|
($usdChangePercent < 0 ? 'heroicon-m-arrow-trending-down' : 'heroicon-m-minus')
|
|
)
|
|
->icon('heroicon-o-banknotes')
|
|
->color(
|
|
$usdChangePercent > 0 ? 'danger' :
|
|
($usdChangePercent < 0 ? 'success' : 'gray')
|
|
)
|
|
->chart(!empty($usdChart) ? $usdChart : [0]),
|
|
|
|
Stat::make('تغییرات امروز',
|
|
ifnex_persian_digits(number_format(
|
|
ExchangeRateHistory::whereDate('created_at', today())->count()
|
|
))
|
|
)
|
|
->description('تغییرات نرخ ثبتشده در امروز')
|
|
->descriptionIcon('heroicon-m-arrow-path')
|
|
->icon('heroicon-o-arrow-path')
|
|
->color('info'),
|
|
|
|
Stat::make('در انتظار تأیید',
|
|
ifnex_persian_digits(number_format($service->getPendingCount()))
|
|
)
|
|
->description('نرخهای پیشنهادی API — منتظر تأیید مدیر')
|
|
->descriptionIcon('heroicon-m-clock')
|
|
->icon('heroicon-o-clock')
|
|
->color('warning'),
|
|
];
|
|
}
|
|
} |