From af7bf05b9116be924c0eb6c2f0b596ffd6c0410e Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 26 Mar 2026 13:02:42 +0700 Subject: [PATCH] feat: Implement a custom Filament profile page for user details and password management, and integrate it into the dashboard panel. --- app/Filament/Pages/Auth/Profile.php | 121 ++++++++++++++++++ .../Filament/DashboardPanelProvider.php | 2 + 2 files changed, 123 insertions(+) create mode 100644 app/Filament/Pages/Auth/Profile.php diff --git a/app/Filament/Pages/Auth/Profile.php b/app/Filament/Pages/Auth/Profile.php new file mode 100644 index 0000000..1c7a179 --- /dev/null +++ b/app/Filament/Pages/Auth/Profile.php @@ -0,0 +1,121 @@ +components([ + Section::make('Informasi Profil 👤') + ->description('Kelola detail profil Anda seperti nama, alamat surel, dan nama pengguna.') + ->icon('heroicon-m-user-circle') + ->schema([ + TextInput::make('name') + ->label('Nama Lengkap') + ->placeholder('Masukkan nama lengkap Anda') + ->required() + ->maxLength(100) + ->prefixIcon('heroicon-m-user'), + + Grid::make(2) + ->schema([ + TextInput::make('email') + ->label('Alamat Surel') + ->placeholder('contoh@email.com') + ->autocomplete(false) + ->required() + ->maxLength(254) + ->unique(ignoreRecord: true) + ->email() + ->prefixIcon('heroicon-m-envelope') + ->live(), + + TextInput::make('username') + ->label('Nama Pengguna') + ->placeholder('nama_pengguna') + ->autocomplete(false) + ->required() + ->minLength(5) + ->maxLength(20) + ->regex('/^[a-zA-Z0-9_.-]+$/') + ->unique(ignoreRecord: true) + ->prefixIcon('heroicon-m-at-symbol'), + ]), + ]), + + Section::make('Keamanan Akun 🔒') + ->description('Pastikan akun Anda menggunakan kata sandi yang panjang dan aman.') + ->icon('heroicon-m-finger-print') + ->schema([ + Grid::make(2) + ->schema([ + TextInput::make('password') + ->label(__('filament-panels::auth/pages/register.form.password.label')) + ->placeholder('********') + ->password() + ->revealable(filament()->arePasswordsRevealable()) + ->required(fn (Get $get) => filled($get('password')) || filled($get('passwordConfirmation'))) + ->rule(Password::default()) + ->showAllValidationMessages() + ->dehydrated(fn ($state) => filled($state)) + ->dehydrateStateUsing(fn ($state) => Hash::make($state)) + ->same('passwordConfirmation') + ->validationAttribute(__('filament-panels::auth/pages/register.form.password.validation_attribute')) + ->prefixIcon('heroicon-m-lock-closed'), + + TextInput::make('passwordConfirmation') + ->label(__('filament-panels::auth/pages/register.form.password_confirmation.label')) + ->placeholder('********') + ->password() + ->revealable(filament()->arePasswordsRevealable()) + ->required(fn (Get $get) => filled($get('password')) || filled($get('passwordConfirmation'))) + ->dehydrated(false) + ->prefixIcon('heroicon-m-shield-check'), + ]), + ]), + ]); + } + + protected function handleRecordUpdate(Model $record, array $data): Model + { + $passwordChanged = filled($data['password'] ?? null); + + $record->update($data); + + CheerfulNotification::success( + 'Profil Berhasil Diperbarui ✅', + 'Data profil Anda telah berhasil disimpan dan diperbarui di dalam sistem.' + )->send(); + + if ($passwordChanged) { + auth()->logout(); + } + + return $record; + } + + protected function getSavedNotification(): ?Notification + { + return null; + } +} diff --git a/app/Providers/Filament/DashboardPanelProvider.php b/app/Providers/Filament/DashboardPanelProvider.php index 39b99c8..c0eb66f 100644 --- a/app/Providers/Filament/DashboardPanelProvider.php +++ b/app/Providers/Filament/DashboardPanelProvider.php @@ -5,6 +5,7 @@ use AchyutN\FilamentLogViewer\FilamentLogViewer; use App\Filament\Pages\Auth\EmailVerification; use App\Filament\Pages\Auth\Login; +use App\Filament\Pages\Auth\Profile; use App\Filament\Pages\Auth\Registration; use App\Filament\Pages\Dashboard; use App\Settings\GeneralSettings; @@ -56,6 +57,7 @@ public function panel(Panel $panel): Panel ->brandLogo(fn () => Storage::disk('public')->url($generalSettings->site_logo)) ->favicon(fn () => Storage::disk('public')->url($generalSettings->site_icon)) ->login(Login::class) + ->profile(Profile::class) ->registration(Registration::class) ->emailVerification(EmailVerification::class) ->colors([