Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(admin): improve UX and implement dashboard #62

Merged
merged 12 commits into from
Feb 21, 2024
5 changes: 5 additions & 0 deletions app/Enums/ApplicationStatus.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

namespace App\Enums;
use Illuminate\Support\Str;

enum ApplicationStatus: string
{
Expand Down Expand Up @@ -157,4 +158,8 @@ function orWhere(\Illuminate\Database\Eloquent\Builder $query)
),
};
}

function displayName(): string {
return Str::of($this->value)->replace('_', ' ')->title()->value();
}
}
58 changes: 58 additions & 0 deletions app/Filament/Widgets/AbstractApplicationTablesChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace App\Filament\Widgets;

use App\Models\Application;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

abstract class AbstractApplicationTablesChart extends ChartWidget
{
protected static ?string $heading = 'Total Tables (active)';
protected static ?string $maxHeight = '200px';

protected function getType(): string
{
return 'pie';
}

abstract protected function retrieveData(): \Illuminate\Support\Collection;

protected function getData(): array
{
$data = $this->retrieveData();
return [
'datasets' => [
[
'label' => 'Total Tables',
'data' => $data->pluck('count')->all(),
'backgroundColor' => [
'rgb(200, 180, 90)',
'rgb(0, 200, 255)',
'rgb(255, 200, 80)',
'rgb(250, 100, 200)',
'rgb(150, 100, 255)',
'rgb(0, 180, 0)',
'rgb(250, 80, 50)',
],
],
],
'labels' => $data->pluck('type')->all(),
];
}

protected function getOptions(): array
{
return [
'scales' => [
'x' => [
'display' => false,
],
'y' => [
'display' => false,
],
],
];
}
}
23 changes: 23 additions & 0 deletions app/Filament/Widgets/ApplicationStats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\Filament\Widgets;

use App\Models\Application;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class ApplicationStats extends BaseWidget
{
protected function getStats(): array
{
$data = Cache::remember('dd-admin-application-stats', 60, fn() => Application::query()->toBase()->select(DB::raw('type, COUNT(*) as count'))->whereNull('canceled_at')->whereNull('waiting_at')->groupBy('type')->get());
return [
Stat::make('Total Applications (active)', fn() => $data->sum('count')),
Stat::make('Total Dealers (active)', fn() => $data->firstWhere('type', 'dealer')?->count ?? 0),
Stat::make('Total Shares (active)', fn() => $data->firstWhere('type', 'share')?->count ?? 0),
Stat::make('Total Assistants (active)', fn() => $data->firstWhere('type', 'assistant')?->count ?? 0),
];
}
}
67 changes: 67 additions & 0 deletions app/Filament/Widgets/ApplicationStatusChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace App\Filament\Widgets;

use App\Enums\ApplicationStatus;
use App\Models\Application;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Facades\Cache;

class ApplicationStatusChart extends ChartWidget
{
protected static ?string $heading = 'Applications by Status';
protected static ?string $maxHeight = '200px';

protected function getType(): string
{
return 'pie';
}

protected function getData(): array
{
$status = Cache::remember('dd-admin-application-status', 60, fn () => [
ApplicationStatus::Canceled->displayName() => ApplicationStatus::Canceled->orWhere(Application::query())->count(),
ApplicationStatus::Open->displayName() => ApplicationStatus::Open->orWhere(Application::query())->count(),
ApplicationStatus::Waiting->displayName() => ApplicationStatus::Waiting->orWhere(Application::query())->count(),
ApplicationStatus::TableAssigned->displayName() => ApplicationStatus::TableAssigned->orWhere(Application::query())->count(),
ApplicationStatus::TableOffered->displayName() => ApplicationStatus::TableOffered->orWhere(Application::query())->count(),
ApplicationStatus::TableAccepted->displayName() => ApplicationStatus::TableAccepted->orWhere(Application::query())->count(),
ApplicationStatus::CheckedIn->displayName() => ApplicationStatus::CheckedIn->orWhere(Application::query())->count(),
ApplicationStatus::CheckedOut->displayName() => ApplicationStatus::CheckedOut->orWhere(Application::query())->count(),
]);

return [
'datasets' => [
[
'label' => 'Total Applications',
'data' => array_values($status),
'backgroundColor' => [
'rgb(250, 80, 80)',
'rgb(0, 200, 255)',
'rgb(255, 200, 80)',
'rgb(250, 100, 200)',
'rgb(150, 100, 255)',
'rgb(100, 255, 100)',
'rgb(0, 180, 0)',
'rgb(120, 120, 120)',
],
],
],
'labels' => array_keys($status),
];
}

protected function getOptions(): array
{
return [
'scales' => [
'x' => [
'display' => false,
],
'y' => [
'display' => false,
],
],
];
}
}
17 changes: 17 additions & 0 deletions app/Filament/Widgets/ApplicationTablesAssignedChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Filament\Widgets;

use App\Models\Application;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class ApplicationTablesAssignedChart extends AbstractApplicationTablesChart
{
protected static ?string $heading = 'Total Tables Assigned (active)';

protected function retrieveData(): \Illuminate\Support\Collection
{
return Cache::remember('dd-admin-application-tables-assigned', 60, fn() => Application::query()->toBase()->join('table_types', 'table_type_assigned', '=', 'table_types.id')->select(DB::raw('COUNT(*) as count, name as type'))->where('type', '=', 'dealer')->whereNull('canceled_at')->whereNull('waiting_at')->groupBy('name')->get());
}
}
17 changes: 17 additions & 0 deletions app/Filament/Widgets/ApplicationTablesRequestedChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace App\Filament\Widgets;

use App\Models\Application;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class ApplicationTablesRequestedChart extends AbstractApplicationTablesChart
{
protected static ?string $heading = 'Total Tables Requested (active)';

protected function retrieveData(): \Illuminate\Support\Collection
{
return Cache::remember('dd-admin-application-tables-requested', 60, fn() => Application::query()->toBase()->join('table_types', 'table_type_requested', '=', 'table_types.id')->select(DB::raw('COUNT(*) as count, name as type'))->where('type', '=', 'dealer')->whereNull('canceled_at')->whereNull('waiting_at')->groupBy('name')->get());
}
}
11 changes: 11 additions & 0 deletions app/Filament/Widgets/DashboardInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace App\Filament\Widgets;

use Filament\Widgets\Widget;

class DashboardInfo extends Widget
{
protected static string $view = 'filament.widgets.dashboard-info';
protected int | string | array $columnSpan = 'full';
}
74 changes: 74 additions & 0 deletions app/Filament/Widgets/RegistrationStatusChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

namespace App\Filament\Widgets;

use App\Http\Controllers\Client\RegSysClientController;
use App\Models\Application;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class RegistrationStatusChart extends ChartWidget
{
protected static ?string $heading = 'Registration Status (active; refresh: 10 minutes)';
protected static ?string $pollingInterval = '3600s';
protected static ?string $maxHeight = '200px';

protected function getType(): string
{
return 'pie';
}

protected function getData(): array
{
$data = Cache::remember('dd-admin-application-totals', 10 * 60, function (): array {
$registrations = RegSysClientController::getAllRegs('id');
return Application::with('user')->whereNull('canceled_at')->whereNull('waiting_at')->get()
->map(fn (Application $application): string => $registrations[$application->user_id]['status'] ?? 'unknown')
->reduce(function (array $statusCount, string $status) {
$statusCount[$status] += 1;
return $statusCount;
}, [
'new' => 0,
'approved' => 0,
'partially paid' => 0,
'paid' => 0,
'checked in' => 0,
'unknown' => 0,
'cancelled' => 0,
]);
});
return [
'datasets' => [
[
'label' => 'Total Applications',
'data' => array_values($data),
'backgroundColor' => [
'rgb(255, 200, 80)',
'rgb(0, 200, 255)',
'rgb(250, 100, 200)',
'rgb(100, 255, 100)',
'rgb(0, 180, 0)',
'rgb(120, 120, 120)',
'rgb(250, 80, 80)',
],
],
],
'labels' => array_keys($data),
];
}

protected function getOptions(): array
{
return [
'scales' => [
'x' => [
'display' => false,
],
'y' => [
'display' => false,
],
],
];
}
}
9 changes: 8 additions & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasAvatar;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Session;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable implements FilamentUser
class User extends Authenticatable implements FilamentUser, HasAvatar
{
use HasApiTokens, HasFactory, Notifiable;
/**
Expand Down Expand Up @@ -81,4 +83,9 @@ public function canAccessPanel(Panel $panel): bool
{
return $this->isAdmin();
}

public function getFilamentAvatarUrl(): ?string
{
return Session::get('avatar');
}
}
20 changes: 13 additions & 7 deletions app/Providers/Filament/AdminPanelProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

namespace App\Providers\Filament;

use Filament\Http\Middleware\Authenticate;
use App\Http\Middleware\Authenticate;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Navigation\NavigationGroup;
use Filament\Navigation\MenuItem;
use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
Expand All @@ -27,7 +27,9 @@ public function panel(Panel $panel): Panel
->default()
->id('admin')
->path('admin')
->login()
->userMenuItems([
'logout' => MenuItem::make()->label('Log out')->url(fn () => route('auth.frontchannel-logout')),
])
->colors([
'primary' => Color::Amber,
])
Expand All @@ -36,10 +38,14 @@ public function panel(Panel $panel): Panel
->pages([
Pages\Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
//->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
->widgets([
Widgets\AccountWidget::class,
Widgets\FilamentInfoWidget::class,
\App\Filament\Widgets\DashboardInfo::class,
\App\Filament\Widgets\ApplicationStats::class,
\App\Filament\Widgets\ApplicationStatusChart::class,
\App\Filament\Widgets\RegistrationStatusChart::class,
\App\Filament\Widgets\ApplicationTablesRequestedChart::class,
\App\Filament\Widgets\ApplicationTablesAssignedChart::class,
])
->middleware([
EncryptCookies::class,
Expand All @@ -56,4 +62,4 @@ public function panel(Panel $panel): Panel
Authenticate::class,
]);
}
}
}
Loading
Loading