From dc1d753cbe31fd37d35a3e6c76494bef8268aef4 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Mon, 30 Mar 2026 16:14:27 +0700 Subject: [PATCH] feat: enhance profile page with student information section and updated layout --- app/Filament/Pages/Profile.php | 216 +++++++++++++++++++++++++-------- 1 file changed, 168 insertions(+), 48 deletions(-) diff --git a/app/Filament/Pages/Profile.php b/app/Filament/Pages/Profile.php index f85c82f..e827f76 100644 --- a/app/Filament/Pages/Profile.php +++ b/app/Filament/Pages/Profile.php @@ -2,92 +2,212 @@ namespace App\Filament\Pages; +use App\Enums\Sex; use App\Filament\Support\SystemNotification; +use Carbon\Carbon; use Filament\Auth\Pages\EditProfile; +use Filament\Forms\Components\DatePicker; +use Filament\Forms\Components\Radio; +use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Notifications\Notification; +use Filament\Schemas\Components\Grid; use Filament\Schemas\Components\Section; -use Filament\Schemas\Components\Utilities\Get; use Filament\Schemas\Schema; +use Filament\Support\Enums\Width; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\Rules\Password; class Profile extends EditProfile { + public function getMaxWidth(): Width + { + return Width::FourExtraLarge; + } + public function form(Schema $schema): Schema { return $schema ->components([ Section::make('Akun') + ->description('Kelola informasi detail akun Anda agar selalu terkini.') + ->icon('heroicon-o-user') ->schema([ - TextInput::make('email') - ->label('Alamat Surel') - ->placeholder('johndoe@puskesmas.com') - ->autocomplete(false) - ->required() - ->maxLength(254) - ->unique(ignoreRecord: true) - ->email() - ->live(), + 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-o-envelope') + ->live(), - TextInput::make('username') - ->label('Nama Pengguna') - ->placeholder('johndoe') - ->autocomplete(false) - ->required() - ->minLength(5) - ->maxLength(20) - ->regex('/^[a-zA-Z0-9_.-]+$/') - ->unique(ignoreRecord: true), + 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-o-at-symbol'), + ]), ]), - Section::make('Kata Sandi') + Section::make('Informasi Mahasiswa') + ->description('Pastikan data akademik Anda sesuai dengan record sistem.') + ->icon('heroicon-o-academic-cap') + ->statePath('student') ->schema([ - TextInput::make('password') - ->label(__('filament-panels::auth/pages/register.form.password.label')) - ->placeholder('********') - ->password() - ->revealable(filament()->arePasswordsRevealable()) - ->required(fn (Get $get) => filled($get('passwoed')) || filled($get('passwordConfirmation'))) - ->rule(Password::default()) - ->showAllValidationMessages() - ->dehydrateStateUsing(fn ($state) => Hash::make($state)) - ->same('passwordConfirmation') - ->validationAttribute(__('filament-panels::auth/pages/register.form.password.validation_attribute')), + TextInput::make('full_name') + ->label('Nama Lengkap') + ->placeholder('John Doe') + ->autocomplete(false) + ->required() + ->maxLength(100) + ->minLength(3) + ->autofocus() + ->columnSpanFull(), - TextInput::make('passwordConfirmation') - ->label(__('filament-panels::auth/pages/register.form.password_confirmation.label')) - ->placeholder('********') - ->password() - ->revealable(filament()->arePasswordsRevealable()) - ->required(fn (Get $get) => filled($get('passwoed')) || filled($get('passwordConfirmation'))) - ->dehydrated(false), + Grid::make(3) + ->schema([ + TextInput::make('student_number') + ->label('NIM') + ->placeholder('1234567890') + ->autocomplete(false) + ->disabled() + ->dehydrated(false), + + TextInput::make('phone_number') + ->label('Nomor Telepon') + ->placeholder('0812 3456 78910') + ->autocomplete(false) + ->required() + ->maxLength(20) + ->minLength(10) + ->rules(['regex:/^[0-9 ]+$/']) + ->mask('9999 9999 99999'), + + Radio::make('sex') + ->label('Jenis Kelamin') + ->options(Sex::class) + ->required() + ->inline(), + ]) + ->columnSpanFull(), + + Textarea::make('address') + ->label('Alamat') + ->placeholder('Jl. Contoh No. 123, Kota, Provinsi') + ->autocomplete(false) + ->rows(3) + ->nullable() + ->columnSpanFull(), + + DatePicker::make('date_of_birth') + ->label('Tanggal Lahir') + ->placeholder('Pilih Tanggal') + ->required() + ->native(false) + ->displayFormat('d F Y') + ->maxDate(Carbon::now()->subYears(15)), + + TextInput::make('place_of_birth') + ->label('Tempat Lahir') + ->placeholder('Purwakarta') + ->autocomplete(false) + ->required() + ->maxLength(50) + ->minLength(3), + ]) + ->columns(2) + ->visible(fn () => auth()->user()?->student()->exists()), + + Section::make('Keamanan Akun') + ->description('Perbarui kata sandi Anda secara berkala untuk menjaga keamanan akun.') + ->icon('heroicon-o-lock-closed') + ->schema([ + Grid::make(2) + ->schema([ + TextInput::make('password') + ->label(__('filament-panels::auth/pages/register.form.password.label')) + ->placeholder('********') + ->password() + ->revealable(filament()->arePasswordsRevealable()) + ->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-o-lock-closed'), + + TextInput::make('passwordConfirmation') + ->label(__('filament-panels::auth/pages/register.form.password_confirmation.label')) + ->placeholder('********') + ->password() + ->revealable(filament()->arePasswordsRevealable()) + ->dehydrated(false) + ->prefixIcon('heroicon-o-lock-closed'), + ]), ]), ]); } + protected function mutateFormDataBeforeFill(array $data): array + { + $student = $this->getUser()->student; + + if ($student) { + $data['student'] = $student->toArray(); + } + + return $data; + } + protected function handleRecordUpdate(Model $record, array $data): Model { - $shouldLogout = false; - if (isset($data['new_password'])) { - $data['password'] = $data['new_password']; - unset($data['new_password']); - $shouldLogout = true; - } + $studentData = $data['student'] ?? null; + unset($data['student']); $record->update($data); + if ($studentData && $record->student) { + $record->student->update($studentData); + } elseif ($studentData) { + $record->student()->create($studentData); + } + + return $record; + } + + protected function afterSave(): void + { SystemNotification::success( 'Profil Berhasil Diperbarui ✅', 'Data profil Anda telah berhasil disimpan dan diperbarui di dalam sistem.' )->send(); - if ($shouldLogout) { - auth()->logout(); - } + if (filled($this->form->getState()['password'] ?? null)) { + filament()->auth()->logout(); + session()->invalidate(); + session()->regenerateToken(); - return $record; + SystemNotification::info( + 'Keamanan Akun Diperbarui 🔐', + 'Anda telah mengubah kata sandi. Untuk alasan keamanan, silakan masuk kembali dengan kata sandi baru Anda.' + )->send(); + + $this->redirect(filament()->getLoginUrl()); + } else { + $this->redirect($this->getUrl()); + } } protected function getSavedNotification(): ?Notification