feat: enhance profile page with student information section and updated layout

This commit is contained in:
Yoga Pangestu 2026-03-30 16:14:27 +07:00
parent 740ebe6a7b
commit dc1d753cbe

View File

@ -2,92 +2,212 @@
namespace App\Filament\Pages; namespace App\Filament\Pages;
use App\Enums\Sex;
use App\Filament\Support\SystemNotification; use App\Filament\Support\SystemNotification;
use Carbon\Carbon;
use Filament\Auth\Pages\EditProfile; 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\Forms\Components\TextInput;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section; use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Schema; use Filament\Schemas\Schema;
use Filament\Support\Enums\Width;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password; use Illuminate\Validation\Rules\Password;
class Profile extends EditProfile class Profile extends EditProfile
{ {
public function getMaxWidth(): Width
{
return Width::FourExtraLarge;
}
public function form(Schema $schema): Schema public function form(Schema $schema): Schema
{ {
return $schema return $schema
->components([ ->components([
Section::make('Akun') Section::make('Akun')
->description('Kelola informasi detail akun Anda agar selalu terkini.')
->icon('heroicon-o-user')
->schema([ ->schema([
TextInput::make('email') Grid::make(2)
->label('Alamat Surel') ->schema([
->placeholder('johndoe@puskesmas.com') TextInput::make('email')
->autocomplete(false) ->label('Alamat Surel')
->required() ->placeholder('contoh@email.com')
->maxLength(254) ->autocomplete(false)
->unique(ignoreRecord: true) ->required()
->email() ->maxLength(254)
->live(), ->unique(ignoreRecord: true)
->email()
->prefixIcon('heroicon-o-envelope')
->live(),
TextInput::make('username') TextInput::make('username')
->label('Nama Pengguna') ->label('Nama Pengguna')
->placeholder('johndoe') ->placeholder('nama_pengguna')
->autocomplete(false) ->autocomplete(false)
->required() ->required()
->minLength(5) ->minLength(5)
->maxLength(20) ->maxLength(20)
->regex('/^[a-zA-Z0-9_.-]+$/') ->regex('/^[a-zA-Z0-9_.-]+$/')
->unique(ignoreRecord: true), ->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([ ->schema([
TextInput::make('password') TextInput::make('full_name')
->label(__('filament-panels::auth/pages/register.form.password.label')) ->label('Nama Lengkap')
->placeholder('********') ->placeholder('John Doe')
->password() ->autocomplete(false)
->revealable(filament()->arePasswordsRevealable()) ->required()
->required(fn (Get $get) => filled($get('passwoed')) || filled($get('passwordConfirmation'))) ->maxLength(100)
->rule(Password::default()) ->minLength(3)
->showAllValidationMessages() ->autofocus()
->dehydrateStateUsing(fn ($state) => Hash::make($state)) ->columnSpanFull(),
->same('passwordConfirmation')
->validationAttribute(__('filament-panels::auth/pages/register.form.password.validation_attribute')),
TextInput::make('passwordConfirmation') Grid::make(3)
->label(__('filament-panels::auth/pages/register.form.password_confirmation.label')) ->schema([
->placeholder('********') TextInput::make('student_number')
->password() ->label('NIM')
->revealable(filament()->arePasswordsRevealable()) ->placeholder('1234567890')
->required(fn (Get $get) => filled($get('passwoed')) || filled($get('passwordConfirmation'))) ->autocomplete(false)
->dehydrated(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 protected function handleRecordUpdate(Model $record, array $data): Model
{ {
$shouldLogout = false; $studentData = $data['student'] ?? null;
if (isset($data['new_password'])) { unset($data['student']);
$data['password'] = $data['new_password'];
unset($data['new_password']);
$shouldLogout = true;
}
$record->update($data); $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( SystemNotification::success(
'Profil Berhasil Diperbarui ✅', 'Profil Berhasil Diperbarui ✅',
'Data profil Anda telah berhasil disimpan dan diperbarui di dalam sistem.' 'Data profil Anda telah berhasil disimpan dan diperbarui di dalam sistem.'
)->send(); )->send();
if ($shouldLogout) { if (filled($this->form->getState()['password'] ?? null)) {
auth()->logout(); 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 protected function getSavedNotification(): ?Notification