components([ Section::make(SystemNotification::getMessage('Akun Pengguna 👤✨', 'Akun')) ->description(SystemNotification::getMessage('Kelola informasi detail akun Anda di sini ya biar nggak kudet! 😉🚀', 'Kelola informasi detail akun Anda agar selalu terkini.')) ->icon(SystemNotification::getNotifStyle() === NotifStyle::Cheerful ? 'heroicon-o-face-smile' : 'heroicon-o-user') ->schema([ 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('nama_pengguna') ->autocomplete(false) ->required() ->minLength(5) ->maxLength(20) ->regex('/^[a-zA-Z0-9_.-]+$/') ->unique(ignoreRecord: true) ->prefixIcon('heroicon-o-at-symbol'), ]), ]), Section::make(SystemNotification::getMessage('Data Mahasiswa 🎓📚', 'Informasi Mahasiswa')) ->description(SystemNotification::getMessage('Pastikan data akademikmu sesuai dengan yang di sistem, jangan sampai salah loh! 🤓📝', 'Pastikan data akademik Anda sesuai dengan record sistem.')) ->icon(SystemNotification::getNotifStyle() === NotifStyle::Cheerful ? 'heroicon-o-academic-cap' : 'heroicon-o-identification') ->statePath('student') ->schema([ TextInput::make('full_name') ->label('Nama Lengkap') ->placeholder('John Doe') ->autocomplete(false) ->required() ->maxLength(100) ->minLength(3) ->columnSpanFull(), 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(SystemNotification::getMessage('Keamanan Akun 🔐⚡', 'Keamanan Akun')) ->description(SystemNotification::getMessage('Rajin-rajin ganti password ya, biar akunmu aman dan nggak dibobol orang! 🕵️‍♂️🛡️', 'Perbarui kata sandi Anda secara berkala untuk menjaga keamanan akun.')) ->icon(SystemNotification::getNotifStyle() === NotifStyle::Cheerful ? 'heroicon-o-shield-check' : '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'), ]), ]), Section::make(SystemNotification::getMessage('Pengaturan Tampilan & UX 🎨✨', 'Preferensi Tampilan')) ->description(SystemNotification::getMessage('Personalisasi pengalaman aplikasi Anda agar lebih nyaman dan sesuai selera! 🌈🚀', 'Sesuaikan gaya bahasa, warna tema, dan jenis huruf aplikasi Anda.')) ->icon(SystemNotification::getNotifStyle() === NotifStyle::Cheerful ? 'heroicon-o-swatch' : 'heroicon-o-paint-brush') ->schema([ Grid::make(2) ->schema([ Select::make('settings.notif_style') ->label('Gaya Bahasa') ->options(NotifStyle::class) ->native(false) ->required(), Select::make('settings.primary_color') ->label('Tema Warna') ->options([ 'blue' => '🔵 Biru (Default)', 'sky' => '💎 Biru Langit', 'cyan' => '🌊 Biru Tosca (Cyan)', 'emerald' => '🟢 Emerald (Hijau)', 'teal' => '🍃 Teal (Hijau Keunguan)', 'lime' => '🍋 Lime (Hijah Muda)', 'amber' => '🟡 Amber (Kuning)', 'orange' => '🟠 Orange', 'rose' => '🔴 Rose (Merah)', 'fuchsia' => '🌸 Fuchsia (Pink Cerah)', 'violet' => '🟣 Violet (Ungu)', 'indigo' => '🌌 Indigo (Ungu Gelap)', ]) ->placeholder('Pilih warna tema') ->native(false), Select::make('settings.font') ->label('Jenis Huruf (Font)') ->options([ 'Inter' => 'Inter (Modern)', 'Roboto' => 'Roboto (Clean)', 'Poppins' => 'Poppins (Rounder)', 'Outfit' => 'Outfit (Premium)', 'Montserrat' => 'Montserrat (Classic)', 'Lexend' => 'Lexend (Readable)', ]) ->native(false), Select::make('settings.content_width') ->label('Lebar Konten') ->options([ 'full' => '↔️ Lebar Penuh (Full)', 'centered' => '🏢 Terpusat (Centered)', ]) ->native(false), Select::make('settings.border_radius') ->label('Radius Sudut (Border)') ->options([ 'none' => '📐 Tegas (Sharp)', 'md' => '📱 Modern (Default)', 'lg' => '🎉 Rounded (Cheerful)', 'xl' => '🎈 Extra Round', ]) ->native(false), Toggle::make('settings.top_navigation') ->label('Navigasi Atas (Top Nav)') ->helperText('Pindahkan menu navigasi dari samping ke bagian atas layar.') ->onIcon('heroicon-m-window') ->offIcon('heroicon-m-arrow-top-right-on-square') ->inline(false), ]), ]), ]); } public function save(): void { try { $this->beginDatabaseTransaction(); $this->callHook('beforeValidate'); $data = $this->form->getState(); $this->callHook('afterValidate'); $data = $this->mutateFormDataBeforeSave($data); $this->callHook('beforeSave'); $this->handleRecordUpdate($this->getUser(), $data); $this->callHook('afterSave'); } catch (Halt $exception) { $exception->shouldRollbackDatabaseTransaction() ? $this->rollBackDatabaseTransaction() : $this->commitDatabaseTransaction(); return; } catch (Throwable $exception) { $this->rollBackDatabaseTransaction(); throw $exception; } $this->commitDatabaseTransaction(); if (request()->hasSession() && array_key_exists('password', $data)) { request()->session()->put([ 'password_hash_'.filament()->getAuthGuard() => $data['password'], ]); } $this->data['password'] = null; $this->data['passwordConfirmation'] = null; $this->getSavedNotification()?->send(); if ($redirectUrl = $this->getRedirectUrl()) { $this->redirect($redirectUrl, navigate: FilamentView::hasSpaMode($redirectUrl)); } } protected function mutateFormDataBeforeFill(array $data): array { $user = $this->getUser(); $student = $user->student; $settings = $user->settings; if ($student) { $data['student'] = $student->toArray(); } if ($settings) { $data['settings'] = $settings->toArray(); } return $data; } protected function handleRecordUpdate(Model $record, array $data): Model { $studentData = $data['student'] ?? null; $settingsData = $data['settings'] ?? null; unset($data['student'], $data['settings']); $record->update($data); /** @var \App\Models\User $record */ if ($studentData && $record->student()->exists()) { $record->student->update($studentData); } elseif ($studentData) { $record->student()->create($studentData); } if ($settingsData && $record->settings()->exists()) { $record->settings->update($settingsData); } elseif ($settingsData) { $record->settings()->create($settingsData); } return $record; } protected function afterSave(): void { SystemNotification::success( 'Profil Berhasil Diperbarui ✅✨', 'Data profil Anda telah berhasil disimpan dan diperbarui. Makin keren deh! 😎🌈', 'Pembaharuan Profil Berhasil', 'Seluruh data profil Anda telah berhasil sinkronisasi dan disimpan dalam database.' )->send(); if (filled($this->form->getState()['password'] ?? null)) { filament()->auth()->logout(); session()->invalidate(); session()->regenerateToken(); SystemNotification::info( 'Keamanan Akun Diperbarui 🔐', 'Anda telah mengubah kata sandi. Demi keamanan, silakan masuk kembali ya! 🚪🔑', 'Pembaruan Kredensial', 'Kata sandi Anda telah berhasil diubah. Harap lakukan otentikasi ulang untuk melanjutkan sesi.' )->send(); $this->redirect(filament()->getLoginUrl()); } else { $this->redirect($this->getUrl()); } } protected function getSavedNotification(): ?Notification { return null; } }