diff --git a/app/Enums/ApplicationStatus.php b/app/Enums/ApplicationStatus.php index 7519ccf..5e6d133 100644 --- a/app/Enums/ApplicationStatus.php +++ b/app/Enums/ApplicationStatus.php @@ -1,6 +1,7 @@ value)->replace('_', ' ')->title()->value(); + } } diff --git a/app/Filament/Widgets/AbstractApplicationTablesChart.php b/app/Filament/Widgets/AbstractApplicationTablesChart.php new file mode 100644 index 0000000..a8b1b75 --- /dev/null +++ b/app/Filament/Widgets/AbstractApplicationTablesChart.php @@ -0,0 +1,58 @@ +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, + ], + ], + ]; + } +} diff --git a/app/Filament/Widgets/ApplicationStats.php b/app/Filament/Widgets/ApplicationStats.php new file mode 100644 index 0000000..cacda99 --- /dev/null +++ b/app/Filament/Widgets/ApplicationStats.php @@ -0,0 +1,23 @@ + 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), + ]; + } +} diff --git a/app/Filament/Widgets/ApplicationStatusChart.php b/app/Filament/Widgets/ApplicationStatusChart.php new file mode 100644 index 0000000..008aa40 --- /dev/null +++ b/app/Filament/Widgets/ApplicationStatusChart.php @@ -0,0 +1,67 @@ + [ + 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, + ], + ], + ]; + } +} diff --git a/app/Filament/Widgets/ApplicationTablesAssignedChart.php b/app/Filament/Widgets/ApplicationTablesAssignedChart.php new file mode 100644 index 0000000..fcba31e --- /dev/null +++ b/app/Filament/Widgets/ApplicationTablesAssignedChart.php @@ -0,0 +1,17 @@ + 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()); + } +} diff --git a/app/Filament/Widgets/ApplicationTablesRequestedChart.php b/app/Filament/Widgets/ApplicationTablesRequestedChart.php new file mode 100644 index 0000000..d91e62c --- /dev/null +++ b/app/Filament/Widgets/ApplicationTablesRequestedChart.php @@ -0,0 +1,17 @@ + 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()); + } +} diff --git a/app/Filament/Widgets/DashboardInfo.php b/app/Filament/Widgets/DashboardInfo.php new file mode 100644 index 0000000..deaef40 --- /dev/null +++ b/app/Filament/Widgets/DashboardInfo.php @@ -0,0 +1,11 @@ +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, + ], + ], + ]; + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 2155eef..aace90e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -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; /** @@ -81,4 +83,9 @@ public function canAccessPanel(Panel $panel): bool { return $this->isAdmin(); } + + public function getFilamentAvatarUrl(): ?string + { + return Session::get('avatar'); + } } diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 6685dd6..1d5757a 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -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; @@ -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, ]) @@ -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, @@ -56,4 +62,4 @@ public function panel(Panel $panel): Panel Authenticate::class, ]); } -} \ No newline at end of file +} diff --git a/resources/views/filament/widgets/dashboard-info.blade.php b/resources/views/filament/widgets/dashboard-info.blade.php new file mode 100644 index 0000000..c86c6ec --- /dev/null +++ b/resources/views/filament/widgets/dashboard-info.blade.php @@ -0,0 +1,51 @@ +@php + $user = filament()->auth()->user(); +@endphp + + + +
+ + +
+

+ Welcome to the Dealers' Den Admin Panel +

+ +

+ {{ filament()->getUserName($user) }} +

+
+ +
+

+ The data on this dashboard will be refreshed every 60 seconds. +

+

+ Applications are considered active if they are neither canceled nor waiting. +

+
+ +
+ @csrf + + + {{ __('filament-panels::widgets/account-widget.actions.logout.label') }} + +
+
+
+
diff --git a/resources/views/layouts/navigation.blade.php b/resources/views/layouts/navigation.blade.php index 44b60fe..182b4d0 100644 --- a/resources/views/layouts/navigation.blade.php +++ b/resources/views/layouts/navigation.blade.php @@ -13,6 +13,20 @@ aria-current="page">Dealers’ Den Rules & Information + + @if (Auth::user()->isFrontdesk()) + + @endif + + @if (Auth::user()->isAdmin()) + + @endif