From 8675c14f1516982ece6976f7b697b5a1cea28cbf Mon Sep 17 00:00:00 2001 From: tuxarmy Date: Fri, 3 Apr 2026 04:27:07 +0700 Subject: [PATCH] feat: tambah seeder roles & super_admin, widget dashboard stats --- app/Filament/Widgets/StatsOverview.php | 38 ++++++++++ app/Policies/ActivityPolicy.php | 75 +++++++++++++++++++ app/Policies/ApprovalPolicy.php | 75 +++++++++++++++++++ app/Policies/AuditPolicy.php | 75 +++++++++++++++++++ app/Policies/CashCategoryPolicy.php | 75 +++++++++++++++++++ app/Policies/CashRecordPolicy.php | 75 +++++++++++++++++++ app/Policies/DivisionPolicy.php | 75 +++++++++++++++++++ app/Policies/UserPolicy.php | 72 ++++++++++++++++++ app/Policies/VotePolicy.php | 75 +++++++++++++++++++ app/Providers/Filament/AdminPanelProvider.php | 2 +- database/seeders/DatabaseSeeder.php | 14 +--- .../seeders/RolesAndPermissionsSeeder.php | 34 +++++++++ 12 files changed, 672 insertions(+), 13 deletions(-) create mode 100644 app/Filament/Widgets/StatsOverview.php create mode 100644 app/Policies/ActivityPolicy.php create mode 100644 app/Policies/ApprovalPolicy.php create mode 100644 app/Policies/AuditPolicy.php create mode 100644 app/Policies/CashCategoryPolicy.php create mode 100644 app/Policies/CashRecordPolicy.php create mode 100644 app/Policies/DivisionPolicy.php create mode 100644 app/Policies/UserPolicy.php create mode 100644 app/Policies/VotePolicy.php create mode 100644 database/seeders/RolesAndPermissionsSeeder.php diff --git a/app/Filament/Widgets/StatsOverview.php b/app/Filament/Widgets/StatsOverview.php new file mode 100644 index 0000000..a43ed5b --- /dev/null +++ b/app/Filament/Widgets/StatsOverview.php @@ -0,0 +1,38 @@ +selectRaw("SUM(CASE WHEN cash_categories.name = 'pemasukan' THEN amount ELSE -amount END) as saldo") + ->value('saldo') ?? 0; + + return [ + Stat::make('Anggota Aktif', User::where('status', 'aktif')->count()) + ->icon('heroicon-o-users') + ->color('success'), + + Stat::make('Total Kas', 'Rp ' . number_format($totalKas, 0, ',', '.')) + ->icon('heroicon-o-banknotes') + ->color($totalKas >= 0 ? 'success' : 'danger'), + + Stat::make('Kegiatan Berjalan', Activity::where('status', 'approved') + ->whereNull('executed_at')->count()) + ->icon('heroicon-o-calendar-days') + ->color('info'), + + Stat::make('Kegiatan Pending', Activity::where('status', 'pending')->count()) + ->icon('heroicon-o-clock') + ->color('warning'), + ]; + } +} diff --git a/app/Policies/ActivityPolicy.php b/app/Policies/ActivityPolicy.php new file mode 100644 index 0000000..91e8221 --- /dev/null +++ b/app/Policies/ActivityPolicy.php @@ -0,0 +1,75 @@ +can('ViewAny:Activity'); + } + + public function view(AuthUser $authUser, Activity $activity): bool + { + return $authUser->can('View:Activity'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:Activity'); + } + + public function update(AuthUser $authUser, Activity $activity): bool + { + return $authUser->can('Update:Activity'); + } + + public function delete(AuthUser $authUser, Activity $activity): bool + { + return $authUser->can('Delete:Activity'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:Activity'); + } + + public function restore(AuthUser $authUser, Activity $activity): bool + { + return $authUser->can('Restore:Activity'); + } + + public function forceDelete(AuthUser $authUser, Activity $activity): bool + { + return $authUser->can('ForceDelete:Activity'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:Activity'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:Activity'); + } + + public function replicate(AuthUser $authUser, Activity $activity): bool + { + return $authUser->can('Replicate:Activity'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:Activity'); + } + +} \ No newline at end of file diff --git a/app/Policies/ApprovalPolicy.php b/app/Policies/ApprovalPolicy.php new file mode 100644 index 0000000..57c1f4e --- /dev/null +++ b/app/Policies/ApprovalPolicy.php @@ -0,0 +1,75 @@ +can('ViewAny:Approval'); + } + + public function view(AuthUser $authUser, Approval $approval): bool + { + return $authUser->can('View:Approval'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:Approval'); + } + + public function update(AuthUser $authUser, Approval $approval): bool + { + return $authUser->can('Update:Approval'); + } + + public function delete(AuthUser $authUser, Approval $approval): bool + { + return $authUser->can('Delete:Approval'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:Approval'); + } + + public function restore(AuthUser $authUser, Approval $approval): bool + { + return $authUser->can('Restore:Approval'); + } + + public function forceDelete(AuthUser $authUser, Approval $approval): bool + { + return $authUser->can('ForceDelete:Approval'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:Approval'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:Approval'); + } + + public function replicate(AuthUser $authUser, Approval $approval): bool + { + return $authUser->can('Replicate:Approval'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:Approval'); + } + +} \ No newline at end of file diff --git a/app/Policies/AuditPolicy.php b/app/Policies/AuditPolicy.php new file mode 100644 index 0000000..df3c74b --- /dev/null +++ b/app/Policies/AuditPolicy.php @@ -0,0 +1,75 @@ +can('ViewAny:Audit'); + } + + public function view(AuthUser $authUser, Audit $audit): bool + { + return $authUser->can('View:Audit'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:Audit'); + } + + public function update(AuthUser $authUser, Audit $audit): bool + { + return $authUser->can('Update:Audit'); + } + + public function delete(AuthUser $authUser, Audit $audit): bool + { + return $authUser->can('Delete:Audit'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:Audit'); + } + + public function restore(AuthUser $authUser, Audit $audit): bool + { + return $authUser->can('Restore:Audit'); + } + + public function forceDelete(AuthUser $authUser, Audit $audit): bool + { + return $authUser->can('ForceDelete:Audit'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:Audit'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:Audit'); + } + + public function replicate(AuthUser $authUser, Audit $audit): bool + { + return $authUser->can('Replicate:Audit'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:Audit'); + } + +} \ No newline at end of file diff --git a/app/Policies/CashCategoryPolicy.php b/app/Policies/CashCategoryPolicy.php new file mode 100644 index 0000000..5cd9857 --- /dev/null +++ b/app/Policies/CashCategoryPolicy.php @@ -0,0 +1,75 @@ +can('ViewAny:CashCategory'); + } + + public function view(AuthUser $authUser, CashCategory $cashCategory): bool + { + return $authUser->can('View:CashCategory'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:CashCategory'); + } + + public function update(AuthUser $authUser, CashCategory $cashCategory): bool + { + return $authUser->can('Update:CashCategory'); + } + + public function delete(AuthUser $authUser, CashCategory $cashCategory): bool + { + return $authUser->can('Delete:CashCategory'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:CashCategory'); + } + + public function restore(AuthUser $authUser, CashCategory $cashCategory): bool + { + return $authUser->can('Restore:CashCategory'); + } + + public function forceDelete(AuthUser $authUser, CashCategory $cashCategory): bool + { + return $authUser->can('ForceDelete:CashCategory'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:CashCategory'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:CashCategory'); + } + + public function replicate(AuthUser $authUser, CashCategory $cashCategory): bool + { + return $authUser->can('Replicate:CashCategory'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:CashCategory'); + } + +} \ No newline at end of file diff --git a/app/Policies/CashRecordPolicy.php b/app/Policies/CashRecordPolicy.php new file mode 100644 index 0000000..c5a8756 --- /dev/null +++ b/app/Policies/CashRecordPolicy.php @@ -0,0 +1,75 @@ +can('ViewAny:CashRecord'); + } + + public function view(AuthUser $authUser, CashRecord $cashRecord): bool + { + return $authUser->can('View:CashRecord'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:CashRecord'); + } + + public function update(AuthUser $authUser, CashRecord $cashRecord): bool + { + return $authUser->can('Update:CashRecord'); + } + + public function delete(AuthUser $authUser, CashRecord $cashRecord): bool + { + return $authUser->can('Delete:CashRecord'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:CashRecord'); + } + + public function restore(AuthUser $authUser, CashRecord $cashRecord): bool + { + return $authUser->can('Restore:CashRecord'); + } + + public function forceDelete(AuthUser $authUser, CashRecord $cashRecord): bool + { + return $authUser->can('ForceDelete:CashRecord'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:CashRecord'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:CashRecord'); + } + + public function replicate(AuthUser $authUser, CashRecord $cashRecord): bool + { + return $authUser->can('Replicate:CashRecord'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:CashRecord'); + } + +} \ No newline at end of file diff --git a/app/Policies/DivisionPolicy.php b/app/Policies/DivisionPolicy.php new file mode 100644 index 0000000..fcba082 --- /dev/null +++ b/app/Policies/DivisionPolicy.php @@ -0,0 +1,75 @@ +can('ViewAny:Division'); + } + + public function view(AuthUser $authUser, Division $division): bool + { + return $authUser->can('View:Division'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:Division'); + } + + public function update(AuthUser $authUser, Division $division): bool + { + return $authUser->can('Update:Division'); + } + + public function delete(AuthUser $authUser, Division $division): bool + { + return $authUser->can('Delete:Division'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:Division'); + } + + public function restore(AuthUser $authUser, Division $division): bool + { + return $authUser->can('Restore:Division'); + } + + public function forceDelete(AuthUser $authUser, Division $division): bool + { + return $authUser->can('ForceDelete:Division'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:Division'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:Division'); + } + + public function replicate(AuthUser $authUser, Division $division): bool + { + return $authUser->can('Replicate:Division'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:Division'); + } + +} \ No newline at end of file diff --git a/app/Policies/UserPolicy.php b/app/Policies/UserPolicy.php new file mode 100644 index 0000000..4da552a --- /dev/null +++ b/app/Policies/UserPolicy.php @@ -0,0 +1,72 @@ +can('ViewAny:User'); + } + + public function view(AuthUser $authUser): bool + { + return $authUser->can('View:User'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:User'); + } + + public function update(AuthUser $authUser): bool + { + return $authUser->can('Update:User'); + } + + public function delete(AuthUser $authUser): bool + { + return $authUser->can('Delete:User'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:User'); + } + + public function restore(AuthUser $authUser): bool + { + return $authUser->can('Restore:User'); + } + + public function forceDelete(AuthUser $authUser): bool + { + return $authUser->can('ForceDelete:User'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:User'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:User'); + } + + public function replicate(AuthUser $authUser): bool + { + return $authUser->can('Replicate:User'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:User'); + } + +} \ No newline at end of file diff --git a/app/Policies/VotePolicy.php b/app/Policies/VotePolicy.php new file mode 100644 index 0000000..165d41a --- /dev/null +++ b/app/Policies/VotePolicy.php @@ -0,0 +1,75 @@ +can('ViewAny:Vote'); + } + + public function view(AuthUser $authUser, Vote $vote): bool + { + return $authUser->can('View:Vote'); + } + + public function create(AuthUser $authUser): bool + { + return $authUser->can('Create:Vote'); + } + + public function update(AuthUser $authUser, Vote $vote): bool + { + return $authUser->can('Update:Vote'); + } + + public function delete(AuthUser $authUser, Vote $vote): bool + { + return $authUser->can('Delete:Vote'); + } + + public function deleteAny(AuthUser $authUser): bool + { + return $authUser->can('DeleteAny:Vote'); + } + + public function restore(AuthUser $authUser, Vote $vote): bool + { + return $authUser->can('Restore:Vote'); + } + + public function forceDelete(AuthUser $authUser, Vote $vote): bool + { + return $authUser->can('ForceDelete:Vote'); + } + + public function forceDeleteAny(AuthUser $authUser): bool + { + return $authUser->can('ForceDeleteAny:Vote'); + } + + public function restoreAny(AuthUser $authUser): bool + { + return $authUser->can('RestoreAny:Vote'); + } + + public function replicate(AuthUser $authUser, Vote $vote): bool + { + return $authUser->can('Replicate:Vote'); + } + + public function reorder(AuthUser $authUser): bool + { + return $authUser->can('Reorder:Vote'); + } + +} \ No newline at end of file diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 7087c3d..ef98aab 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -40,7 +40,7 @@ class AdminPanelProvider extends PanelProvider ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets') ->widgets([ AccountWidget::class, - FilamentInfoWidget::class, + \App\Filament\Widgets\StatsOverview::class, ]) ->middleware([ EncryptCookies::class, diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 6b901f8..6ccb4cb 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,24 +2,14 @@ namespace Database\Seeders; -use App\Models\User; -use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { - use WithoutModelEvents; - - /** - * Seed the application's database. - */ public function run(): void { - // User::factory(10)->create(); - - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', + $this->call([ + RolesAndPermissionsSeeder::class, ]); } } diff --git a/database/seeders/RolesAndPermissionsSeeder.php b/database/seeders/RolesAndPermissionsSeeder.php new file mode 100644 index 0000000..a373dd6 --- /dev/null +++ b/database/seeders/RolesAndPermissionsSeeder.php @@ -0,0 +1,34 @@ +forgetCachedPermissions(); + + $roles = ['super_admin', 'ketua', 'bendahara', 'pengurus', 'anggota', 'auditor']; + + foreach ($roles as $role) { + Role::firstOrCreate(['name' => $role, 'guard_name' => 'web']); + } + + // super_admin mendapat semua permission via Shield config + $superAdmin = User::firstOrCreate( + ['email' => 'admin@persegi.id'], + [ + 'name' => 'Super Admin', + 'password' => bcrypt('password'), + 'phone' => '08123456789', + 'status' => 'aktif', + ] + ); + + $superAdmin->assignRole('super_admin'); + } +}