feat: Implement global date range filtering across all dashboard widgets and add corresponding UI controls to the dashboard page.
This commit is contained in:
parent
8f1cb16dc9
commit
a62ea370f4
@ -2,11 +2,13 @@
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Pages\Dashboard as BaseDashboard;
|
||||
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
|
||||
use Filament\Schemas\Components\Fieldset;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
|
||||
class Dashboard extends BaseDashboard
|
||||
{
|
||||
@ -20,16 +22,36 @@ public function filtersForm(Schema $schema): Schema
|
||||
->schema([
|
||||
DatePicker::make('startDate')
|
||||
->label('Tanggal Mulai')
|
||||
->placeholder('Pilih tanggal mulai')
|
||||
->native(false)
|
||||
->placeholder('Pilih tanggal mulai'),
|
||||
->displayFormat('l, d F Y'),
|
||||
|
||||
DatePicker::make('endDate')
|
||||
->label('Tanggal Selesai')
|
||||
->placeholder('Pilih tanggal selesai')
|
||||
->native(false)
|
||||
->placeholder('Pilih tanggal selesai'),
|
||||
->displayFormat('l, d F Y'),
|
||||
])
|
||||
->columns(2)
|
||||
->columnSpanFull(),
|
||||
])
|
||||
->columns(2);
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('reset')
|
||||
->label('Reset Filter')
|
||||
->icon(Heroicon::XMark)
|
||||
->color('danger')
|
||||
->action(fn () => $this->resetFilters())
|
||||
->visible(fn () => ! empty($this->filters['startDate']) || ! empty($this->filters['endDate'])),
|
||||
];
|
||||
}
|
||||
|
||||
public function resetFilters(): void
|
||||
{
|
||||
$this->filters['startDate'] = null;
|
||||
$this->filters['endDate'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
class CooperationStatusChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Status Kerjasama';
|
||||
|
||||
protected static ?int $sort = 9;
|
||||
@ -16,7 +18,12 @@ class CooperationStatusChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = Cooperation::query()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->selectRaw('status, count(*) as total')
|
||||
->groupBy('status')
|
||||
->get();
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
class IssueLocationChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Sebaran Isu Berdasarkan Wilayah';
|
||||
|
||||
protected static ?int $sort = 15;
|
||||
@ -17,11 +19,16 @@ class IssueLocationChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$issueTable = (new IssueManagement)->getTable();
|
||||
$locationTable = (new Location)->getTable();
|
||||
|
||||
$data = IssueManagement::query()
|
||||
->join($locationTable, "{$issueTable}.location_id", '=', "{$locationTable}.id")
|
||||
->when($startDate, fn ($q) => $q->whereDate("{$issueTable}.created_at", '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate("{$issueTable}.created_at", '<=', $endDate))
|
||||
->select("{$locationTable}.name", DB::raw('count(*) as total'))
|
||||
->groupBy("{$locationTable}.id", "{$locationTable}.name")
|
||||
->orderByDesc('total')
|
||||
|
||||
@ -10,14 +10,24 @@
|
||||
|
||||
class JournalistMetricsStats extends BaseWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected static ?int $sort = 7;
|
||||
|
||||
protected int|string|array $columnSpan = 1;
|
||||
|
||||
protected function getStats(): array
|
||||
{
|
||||
$totalJournalists = Journalist::count();
|
||||
$totalMedia = PartnerMedia::count();
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$totalJournalists = Journalist::when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count();
|
||||
|
||||
$totalMedia = PartnerMedia::when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count();
|
||||
|
||||
$average = $totalMedia > 0 ? round($totalJournalists / $totalMedia, 1) : 0;
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
class JournalistRegistrationChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Tren Pertambahan Jurnalis';
|
||||
|
||||
protected static ?int $sort = 8;
|
||||
@ -17,12 +19,17 @@ class JournalistRegistrationChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = Journalist::query()
|
||||
->select(
|
||||
DB::raw('COUNT(*) as count'),
|
||||
DB::raw("DATE_FORMAT(created_at, '%Y-%m') as month")
|
||||
)
|
||||
->where('created_at', '>=', now()->subMonths(6))
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when(! $startDate, fn ($q) => $q->where('created_at', '>=', now()->subMonths(6)))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->groupBy('month')
|
||||
->orderBy('month')
|
||||
->get();
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
|
||||
class JournalistUkwChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Status Sertifikasi UKW Jurnalis';
|
||||
|
||||
protected static ?int $sort = 6;
|
||||
@ -15,14 +17,22 @@ class JournalistUkwChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$certified = Journalist::whereNotNull('ukw_certificate')
|
||||
->where('ukw_certificate', '!=', '')
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count();
|
||||
|
||||
$notCertified = Journalist::where(function ($query) {
|
||||
$query->whereNull('ukw_certificate')
|
||||
->orWhere('ukw_certificate', '');
|
||||
})->count();
|
||||
})
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count();
|
||||
|
||||
return [
|
||||
'datasets' => [
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
class MediaClassificationChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Klasifikasi Media';
|
||||
|
||||
protected static ?int $sort = 3;
|
||||
@ -16,7 +18,12 @@ class MediaClassificationChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = PartnerMedia::query()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->selectRaw('classification, count(*) as total')
|
||||
->groupBy('classification')
|
||||
->get();
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
class MediaCooperationRankingChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Ranking Media (Kerjasama Disetujui)';
|
||||
|
||||
protected static ?int $sort = 11;
|
||||
@ -17,9 +19,14 @@ class MediaCooperationRankingChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = PartnerMedia::query()
|
||||
->join('cooperation_media', 'partner_media.id', '=', 'cooperation_media.partner_media_id')
|
||||
->where('cooperation_media.status', ApprovalStatus::ACCEPTED)
|
||||
->when($startDate, fn ($q) => $q->whereDate('cooperation_media.created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('cooperation_media.created_at', '<=', $endDate))
|
||||
->select('partner_media.name', DB::raw('count(*) as total'))
|
||||
->groupBy('partner_media.id', 'partner_media.name')
|
||||
->orderByDesc('total')
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
class MediaRegistrationChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Tren Pendaftaran Media';
|
||||
|
||||
protected static ?int $sort = 4;
|
||||
@ -17,12 +19,17 @@ class MediaRegistrationChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = PartnerMedia::query()
|
||||
->select(
|
||||
DB::raw('COUNT(*) as count'),
|
||||
DB::raw("DATE_FORMAT(created_at, '%Y-%m') as month")
|
||||
)
|
||||
->where('created_at', '>=', now()->subMonths(6))
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when(! $startDate, fn ($q) => $q->where('created_at', '>=', now()->subMonths(6)))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->groupBy('month')
|
||||
->orderBy('month')
|
||||
->get();
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
class MediaTypeChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Distribusi Jenis Media';
|
||||
|
||||
protected static ?int $sort = 2;
|
||||
@ -16,7 +18,12 @@ class MediaTypeChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = PartnerMedia::query()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->selectRaw('type, count(*) as total')
|
||||
->groupBy('type')
|
||||
->get();
|
||||
|
||||
@ -14,39 +14,59 @@
|
||||
|
||||
class OverviewStats extends BaseWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected static ?int $sort = 1;
|
||||
|
||||
protected int|string|array $columnSpan = 'full';
|
||||
|
||||
protected function getStats(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
return [
|
||||
Stat::make('Total Perusahaan', Company::count())
|
||||
Stat::make('Total Perusahaan', Company::when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count())
|
||||
->description('Perusahaan terdaftar')
|
||||
->descriptionIcon(Heroicon::BuildingOffice2)
|
||||
->color('primary'),
|
||||
|
||||
Stat::make('Media Terverifikasi', PartnerMedia::approved()->count())
|
||||
Stat::make('Media Terverifikasi', PartnerMedia::approved()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count())
|
||||
->description('Media aktif')
|
||||
->descriptionIcon(Heroicon::CheckBadge)
|
||||
->color('success'),
|
||||
|
||||
Stat::make('Total Jurnalis', Journalist::count())
|
||||
Stat::make('Total Jurnalis', Journalist::when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count())
|
||||
->description('Jurnalis terdaftar')
|
||||
->descriptionIcon(Heroicon::Identification)
|
||||
->color('info'),
|
||||
|
||||
Stat::make('Antrean Verifikasi', VerificationRequest::pending()->count())
|
||||
Stat::make('Antrean Verifikasi', VerificationRequest::pending()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count())
|
||||
->description('Butuh tindakan')
|
||||
->descriptionIcon(Heroicon::PencilSquare)
|
||||
->color('warning'),
|
||||
|
||||
Stat::make('Antrean Perubahan', DataChangeRequest::pending()->count())
|
||||
Stat::make('Antrean Perubahan', DataChangeRequest::pending()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->count())
|
||||
->description('Perubahan data')
|
||||
->descriptionIcon(Heroicon::DocumentText)
|
||||
->color('warning'),
|
||||
|
||||
Stat::make('Total Pengunjung', Visitor::count())
|
||||
Stat::make('Total Pengunjung', Visitor::when($startDate, fn ($q) => $q->whereDate('date', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('date', '<=', $endDate))
|
||||
->count())
|
||||
->description('Total traffic')
|
||||
->descriptionIcon(Heroicon::ChartBar)
|
||||
->color('info'),
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
|
||||
class PopularNewsChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Berita Terpopuler';
|
||||
|
||||
protected static ?int $sort = 13;
|
||||
@ -15,7 +17,12 @@ class PopularNewsChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = News::query()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->orderByDesc('views')
|
||||
->limit(10)
|
||||
->get();
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
class TaskRealizationChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Realisasi Penugasan (Laporan)';
|
||||
|
||||
protected static ?int $sort = 10;
|
||||
@ -17,13 +19,18 @@ class TaskRealizationChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = Report::query()
|
||||
->select(
|
||||
DB::raw('COUNT(*) as count'),
|
||||
DB::raw('status'),
|
||||
DB::raw("DATE_FORMAT(created_at, '%Y-%m') as month")
|
||||
)
|
||||
->where('created_at', '>=', now()->subMonths(6))
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when(! $startDate, fn ($q) => $q->where('created_at', '>=', now()->subMonths(6)))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->groupBy('month', 'status')
|
||||
->orderBy('month')
|
||||
->get();
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
|
||||
class TopMediaJournalistChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Top Media Berdasarkan Jumlah Jurnalis';
|
||||
|
||||
protected static ?int $sort = 5;
|
||||
@ -15,7 +17,12 @@ class TopMediaJournalistChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = PartnerMedia::query()
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->withCount('journalists')
|
||||
->orderByDesc('journalists_count')
|
||||
->limit(10)
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
|
||||
class VerificationPerformanceChart extends ChartWidget
|
||||
{
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Performa Verifikasi (Approved vs Rejected)';
|
||||
|
||||
protected static ?int $sort = 14;
|
||||
@ -18,6 +20,9 @@ class VerificationPerformanceChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = VerificationRequest::query()
|
||||
->select(
|
||||
DB::raw('COUNT(*) as count'),
|
||||
@ -25,7 +30,9 @@ protected function getData(): array
|
||||
DB::raw("DATE_FORMAT(created_at, '%Y-%m') as month")
|
||||
)
|
||||
->whereIn('status', [VerificationStatus::APPROVED, VerificationStatus::REJECTED])
|
||||
->where('created_at', '>=', now()->subMonths(6))
|
||||
->when($startDate, fn ($q) => $q->whereDate('created_at', '>=', $startDate))
|
||||
->when(! $startDate, fn ($q) => $q->where('created_at', '>=', now()->subMonths(6)))
|
||||
->when($endDate, fn ($q) => $q->whereDate('created_at', '<=', $endDate))
|
||||
->groupBy('month', 'status')
|
||||
->orderBy('month')
|
||||
->get();
|
||||
|
||||
@ -9,7 +9,9 @@
|
||||
|
||||
class VisitorTrafficChart extends ChartWidget
|
||||
{
|
||||
protected ?string $heading = 'Traffic Pengunjung (30 Hari Terakhir)';
|
||||
use \Filament\Widgets\Concerns\InteractsWithPageFilters;
|
||||
|
||||
protected ?string $heading = 'Traffic Pengunjung';
|
||||
|
||||
protected static ?int $sort = 12;
|
||||
|
||||
@ -17,12 +19,17 @@ class VisitorTrafficChart extends ChartWidget
|
||||
|
||||
protected function getData(): array
|
||||
{
|
||||
$startDate = $this->filters['startDate'] ?? null;
|
||||
$endDate = $this->filters['endDate'] ?? null;
|
||||
|
||||
$data = Visitor::query()
|
||||
->select(
|
||||
DB::raw('SUM(counter) as total'),
|
||||
DB::raw("DATE_FORMAT(date, '%Y-%m-%d') as day")
|
||||
)
|
||||
->where('date', '>=', now()->subDays(30))
|
||||
->when($startDate, fn ($q) => $q->whereDate('date', '>=', $startDate))
|
||||
->when(! $startDate, fn ($q) => $q->where('date', '>=', now()->subDays(30)))
|
||||
->when($endDate, fn ($q) => $q->whereDate('date', '<=', $endDate))
|
||||
->groupBy('day')
|
||||
->orderBy('day')
|
||||
->get();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user