simedkom/app/Filament/Resources/Master/Users/UserResource.php
Yoga Pangestu 2983cd243f refactor: centralize cheerful notifications and cleanup auth calls
- Introduce `CheerfulNotification` utility class to standardize cheerful and expressive notifications across the application.
- Refactor custom "Cheerful" actions (Create, Edit, Delete, etc.) and `DefaultBulkActions` to utilize the new utility class.
- Update all `ToggleColumn` status updates in Master Data modules to use `CheerfulNotification::statusUpdated()`.
- Replace inline `Notification::make()` calls in custom actions (Reply, Crawl News, Cooperation actions) and Resource Pages with `CheerfulNotification` methods.
- Address various lint errors by standardizing the use of the `Auth` facade and improving type hinting for the authenticated `User` model.
2026-01-14 09:54:46 +07:00

198 lines
7.1 KiB
PHP

<?php
namespace App\Filament\Resources\Master\Users;
use App\Enums\IsActive;
use App\Enums\RoleEnum;
use App\Filament\Actions\Cheerful\DeleteAction;
use App\Filament\Actions\Cheerful\EditAction;
use App\Filament\Actions\Cheerful\ForceDeleteAction;
use App\Filament\Actions\Cheerful\RestoreAction;
use App\Filament\Actions\DefaultBulkActions;
use App\Filament\Columns\TimestampColumns;
use App\Filament\Resources\Master\Users\Pages\ManageUsers;
use App\Models\User;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Enums\Width;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ToggleColumn;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Facades\DB;
use UnitEnum;
class UserResource extends Resource
{
protected static ?string $model = User::class;
protected static string|UnitEnum|null $navigationGroup = 'Master';
protected static string|BackedEnum|null $navigationIcon = Heroicon::UserGroup;
protected static ?string $navigationLabel = 'Pengguna';
protected static ?int $navigationSort = 8;
protected static ?string $recordTitleAttribute = 'name';
protected static ?string $slug = 'master/users';
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label('Nama')
->placeholder('John Doe')
->autocomplete(false)
->autofocus()
->required()
->maxLength(100),
TextInput::make('email')
->label('Alamat Surel')
->placeholder('johndoe@simedkom.purwakartakab.co.id')
->autocomplete(false)
->required()
->maxLength(254)
->email()
->unique(ignoreRecord: true),
TextInput::make('username')
->label('Nama Pengguna')
->placeholder('johndoe')
->autocomplete(false)
->required()
->minLength(5)
->maxLength(20)
->regex('/^[a-zA-Z0-9_.-]+$/')
->unique(ignoreRecord: true),
Select::make('roles')
->label('Peran')
->required()
->relationship('roles', 'name', function (Builder $query): Builder {
return $query->whereNotIn('name', [RoleEnum::DEVELOPER, RoleEnum::PERUSAHAAN]);
})
->multiple()
->preload()
->searchable()
->autocomplete(false),
Hidden::make('password')
->default(fn (?User $record): ?string => $record ? null : config('auth.password_default')),
])
->columns(1);
}
public static function table(Table $table): Table
{
return $table
->recordTitleAttribute('name')
->columns([
TextColumn::make('name')
->label('Nama')
->searchable()
->sortable(),
TextColumn::make('email')
->label('Alamat Surel')
->searchable()
->sortable(),
TextColumn::make('username')
->label('Nama Pengguna')
->searchable()
->sortable(),
ToggleColumn::make('is_active')
->label('Status')
->sortable()
->getStateUsing(fn (User $record): bool => $record->is_active === IsActive::ACTIVE)
->updateStateUsing(function (User $record, bool $state): void {
$record->is_active = $state ? IsActive::ACTIVE : IsActive::INACTIVE;
$record->save();
if ($record->is_active === IsActive::INACTIVE) {
DB::table('sessions')
->where('user_id', $record->id)
->delete();
}
Notification::make()
->title($state ? 'Pengguna Diaktifkan! ✅' : 'Pengguna Dinonaktifkan ⛔')
->body($state ? 'Status akun pengguna berhasil diaktifkan kembali. Siap beraksi! 🚀' : 'Status akun pengguna berhasil dinonaktifkan. Istirahat dulu ya... 😴')
->success()
->send();
})
->disabled(fn (User $record): bool => $record->hasRole(RoleEnum::PERUSAHAAN->value)),
TextColumn::make('roles.name')
->label('Peran')
->searchable()
->sortable()
->badge()
->getStateUsing(fn (User $record): array => $record->roles->pluck('name', 'id')->toArray()),
...TimestampColumns::make(),
])
->filters([
TrashedFilter::make()
->native(false),
])
->recordActions([
EditAction::make()
->modalWidth(Width::Large)
->hidden(fn (User $record): bool => $record->hasRole(RoleEnum::PERUSAHAAN->value)),
DeleteAction::make()
->hidden(fn (User $record): bool => $record->hasRole(RoleEnum::PERUSAHAAN->value)),
ForceDeleteAction::make()
->hidden(fn (User $record): bool => $record->hasRole(RoleEnum::PERUSAHAAN->value)),
RestoreAction::make()
->hidden(fn (User $record): bool => $record->hasRole(RoleEnum::PERUSAHAAN->value)),
])
->toolbarActions([
BulkActionGroup::make([
...DefaultBulkActions::make('Pengguna'),
]),
])
->emptyStateIcon(Heroicon::UserGroup)
->emptyStateDescription('Setelah Anda membubat data pertama, maka akan muncul disini.')
->defaultSort('created_at', 'desc')
->deferFilters(false);
}
public static function getPages(): array
{
return [
'index' => ManageUsers::route('/'),
];
}
public static function getRecordRouteBindingEloquentQuery(): Builder
{
return parent::getRecordRouteBindingEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
public static function getEloquentQuery(): Builder
{
return static::getModel()::query()->withoutDeveloper();
}
}