From b0ff9fddae3f7ee8f746e2fe4dea0dfcaab4a801 Mon Sep 17 00:00:00 2001 From: BrunaDomingues Date: Sun, 26 Jul 2026 20:51:54 -0300 Subject: [PATCH 1/6] fix(panel-app): use Filament DatePicker for profile birthdate Replace the native date input with a non-native Filament DatePicker in a personal section so adjacent-month days are no longer ambiguous. Fixes #397 Co-authored-by: Cursor --- .../components/profile-media-header.blade.php | 30 +------------------ .../panel-app/src/Pages/ProfilePage.php | 21 +++++++++++++ .../tests/Feature/ProfilePageTest.php | 5 +++- 3 files changed, 26 insertions(+), 30 deletions(-) diff --git a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php index d1057003..911cd2d5 100644 --- a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php +++ b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php @@ -47,7 +47,7 @@ class="absolute top-3 right-3 z-20 rounded-full bg-black/60 p-1.5 text-white tra @endif - {{-- Bottom section: avatar + fields --}} + {{-- Bottom section: avatar --}}
{{-- Avatar (overlapping cover) --}}
-
- - -
-
- - -
-
diff --git a/app-modules/panel-app/src/Pages/ProfilePage.php b/app-modules/panel-app/src/Pages/ProfilePage.php index 350b4d02..cfba6270 100644 --- a/app-modules/panel-app/src/Pages/ProfilePage.php +++ b/app-modules/panel-app/src/Pages/ProfilePage.php @@ -97,6 +97,27 @@ public function form(Schema $schema): Schema return $schema ->components([ Form::make([ + Section::make(__('panel-app::profile.sections.personal')) + ->schema([ + Grid::make(2)->schema([ + TextInput::make('nickname') + ->label(__('panel-app::profile.fields.nickname')) + ->placeholder(__('panel-app::profile.placeholders.nickname')) + ->maxLength(100) + ->live(onBlur: true) + ->columnSpan(1), + + DatePicker::make('birthdate') + ->label(__('panel-app::profile.fields.birthdate')) + ->native(condition: false) + ->displayFormat('d/m/Y') + ->format('Y-m-d') + ->minDate(now()->subYears(120)) + ->maxDate(now()) + ->columnSpan(1), + ]), + ]), + Section::make(__('panel-app::profile.sections.professional')) ->schema([ Grid::make(3)->schema([ diff --git a/app-modules/panel-app/tests/Feature/ProfilePageTest.php b/app-modules/panel-app/tests/Feature/ProfilePageTest.php index 23f01970..3d871ebc 100644 --- a/app-modules/panel-app/tests/Feature/ProfilePageTest.php +++ b/app-modules/panel-app/tests/Feature/ProfilePageTest.php @@ -74,19 +74,22 @@ test('profile page saves all fields', function (): void { livewire(ProfilePage::class) - ->set('data.nickname', 'Dan') ->fillForm([ + 'nickname' => 'Dan', + 'birthdate' => '1996-02-15', 'headline' => 'Backend Developer', 'seniority_level' => 'mid', 'years_experience' => 5, 'about' => 'Dev PHP apaixonado por Laravel', ]) ->call('save') + ->assertHasNoFormErrors() ->assertNotified(); $this->profile->refresh(); expect($this->profile->nickname)->toBe('Dan') + ->and($this->profile->birthdate?->format('Y-m-d'))->toBe('1996-02-15') ->and($this->profile->headline)->toBe('Backend Developer') ->and($this->profile->seniority_level)->toBe(SeniorityLevel::Mid) ->and($this->profile->years_experience)->toBe(5) From 11ae8a2d7d7aa8d4ea0a85ca12e381765ae7df9c Mon Sep 17 00:00:00 2001 From: BrunaDomingues Date: Sun, 26 Jul 2026 20:53:18 -0300 Subject: [PATCH 2/6] style(panel-app): highlight today in date picker calendar Make the current day easier to spot in dark mode with primary text and a ring. Co-authored-by: Cursor --- resources/css/filament/app/theme.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/css/filament/app/theme.css b/resources/css/filament/app/theme.css index 0d56f1f5..f1ccdaa9 100644 --- a/resources/css/filament/app/theme.css +++ b/resources/css/filament/app/theme.css @@ -69,3 +69,8 @@ .fi-sidebar { @apply border-e border-gray-200 dark:border-white/10; } + +/* Make "today" stand out in date pickers (esp. dark mode) */ +.fi-fo-date-time-picker-calendar-day.fi-fo-date-time-picker-calendar-day-today:not(.fi-selected):not(.fi-disabled) { + @apply font-semibold text-primary-600 ring-1 ring-inset ring-primary-500/50 dark:text-primary-300 dark:ring-primary-400/60; +} From 0d60ea6738a0f17e09d382e75d7ce159087fa209 Mon Sep 17 00:00:00 2001 From: BrunaDomingues Date: Sun, 26 Jul 2026 20:53:49 -0300 Subject: [PATCH 3/6] fix(panel-app): open birthdate calendar from suffix icon Add a calendar icon to the birthdate field and open the picker when the icon is clicked. Co-authored-by: Cursor --- app-modules/panel-app/src/Pages/ProfilePage.php | 10 ++++++++++ resources/css/filament/app/theme.css | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/app-modules/panel-app/src/Pages/ProfilePage.php b/app-modules/panel-app/src/Pages/ProfilePage.php index cfba6270..654982b7 100644 --- a/app-modules/panel-app/src/Pages/ProfilePage.php +++ b/app-modules/panel-app/src/Pages/ProfilePage.php @@ -24,6 +24,7 @@ use Filament\Schemas\Components\Utilities\Set; use Filament\Schemas\Schema; use Filament\Support\Enums\Width; +use Filament\Support\Icons\Heroicon; use He4rt\Gamification\Character\Models\Character; use He4rt\Identity\User\Models\User; use He4rt\Profile\Actions\SyncProfileSkills; @@ -114,6 +115,15 @@ public function form(Schema $schema): Schema ->format('Y-m-d') ->minDate(now()->subYears(120)) ->maxDate(now()) + ->suffixIcon(Heroicon::Calendar, isInline: true) + ->extraAttributes([ + // Suffix icon sits outside the trigger button; open the panel on icon click. + 'x-on:click' => <<<'JS' + if (! $event.target.closest('.fi-input-wrp-suffix')) return; + if ($event.target.closest('.fi-input-wrp-actions')) return; + $el.querySelector('button.fi-fo-date-time-picker-trigger')?.click(); + JS, + ]) ->columnSpan(1), ]), ]), diff --git a/resources/css/filament/app/theme.css b/resources/css/filament/app/theme.css index f1ccdaa9..5fc7ba0e 100644 --- a/resources/css/filament/app/theme.css +++ b/resources/css/filament/app/theme.css @@ -74,3 +74,8 @@ .fi-fo-date-time-picker-calendar-day.fi-fo-date-time-picker-calendar-day-today:not(.fi-selected):not(.fi-disabled) { @apply font-semibold text-primary-600 ring-1 ring-inset ring-primary-500/50 dark:text-primary-300 dark:ring-primary-400/60; } + +/* Calendar suffix icon should feel clickable */ +.fi-fo-date-time-picker .fi-input-wrp-suffix { + @apply cursor-pointer; +} From 3288f3ee1a006e75be1b42883657e3d10fff414b Mon Sep 17 00:00:00 2001 From: BrunaDomingues Date: Sun, 26 Jul 2026 21:02:54 -0300 Subject: [PATCH 4/6] fix(panel-app): keep nickname outside Filament form Leave the nickname input in the media header so this change stays compatible with the nickname validation flow in #401. Only birthdate moves to the DatePicker. Co-authored-by: Cursor --- .../components/profile-media-header.blade.php | 17 +++++++- .../panel-app/src/Pages/ProfilePage.php | 42 +++++++------------ .../tests/Feature/ProfilePageTest.php | 2 +- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php index 911cd2d5..dbfa5e1c 100644 --- a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php +++ b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php @@ -47,7 +47,7 @@ class="absolute top-3 right-3 z-20 rounded-full bg-black/60 p-1.5 text-white tra @endif - {{-- Bottom section: avatar --}} + {{-- Bottom section: avatar + nickname --}}
{{-- Avatar (overlapping cover) --}}
+ + +
diff --git a/app-modules/panel-app/src/Pages/ProfilePage.php b/app-modules/panel-app/src/Pages/ProfilePage.php index 654982b7..2d35c0ec 100644 --- a/app-modules/panel-app/src/Pages/ProfilePage.php +++ b/app-modules/panel-app/src/Pages/ProfilePage.php @@ -100,32 +100,22 @@ public function form(Schema $schema): Schema Form::make([ Section::make(__('panel-app::profile.sections.personal')) ->schema([ - Grid::make(2)->schema([ - TextInput::make('nickname') - ->label(__('panel-app::profile.fields.nickname')) - ->placeholder(__('panel-app::profile.placeholders.nickname')) - ->maxLength(100) - ->live(onBlur: true) - ->columnSpan(1), - - DatePicker::make('birthdate') - ->label(__('panel-app::profile.fields.birthdate')) - ->native(condition: false) - ->displayFormat('d/m/Y') - ->format('Y-m-d') - ->minDate(now()->subYears(120)) - ->maxDate(now()) - ->suffixIcon(Heroicon::Calendar, isInline: true) - ->extraAttributes([ - // Suffix icon sits outside the trigger button; open the panel on icon click. - 'x-on:click' => <<<'JS' - if (! $event.target.closest('.fi-input-wrp-suffix')) return; - if ($event.target.closest('.fi-input-wrp-actions')) return; - $el.querySelector('button.fi-fo-date-time-picker-trigger')?.click(); - JS, - ]) - ->columnSpan(1), - ]), + DatePicker::make('birthdate') + ->label(__('panel-app::profile.fields.birthdate')) + ->native(condition: false) + ->displayFormat('d/m/Y') + ->format('Y-m-d') + ->minDate(now()->subYears(120)) + ->maxDate(now()) + ->suffixIcon(Heroicon::Calendar, isInline: true) + ->extraAttributes([ + // Suffix icon sits outside the trigger button; open the panel on icon click. + 'x-on:click' => <<<'JS' + if (! $event.target.closest('.fi-input-wrp-suffix')) return; + if ($event.target.closest('.fi-input-wrp-actions')) return; + $el.querySelector('button.fi-fo-date-time-picker-trigger')?.click(); + JS, + ]), ]), Section::make(__('panel-app::profile.sections.professional')) diff --git a/app-modules/panel-app/tests/Feature/ProfilePageTest.php b/app-modules/panel-app/tests/Feature/ProfilePageTest.php index 3d871ebc..89242cc0 100644 --- a/app-modules/panel-app/tests/Feature/ProfilePageTest.php +++ b/app-modules/panel-app/tests/Feature/ProfilePageTest.php @@ -74,8 +74,8 @@ test('profile page saves all fields', function (): void { livewire(ProfilePage::class) + ->set('data.nickname', 'Dan') ->fillForm([ - 'nickname' => 'Dan', 'birthdate' => '1996-02-15', 'headline' => 'Backend Developer', 'seniority_level' => 'mid', From b54872d369c751f8e9c7c962d07e74033ccc110f Mon Sep 17 00:00:00 2001 From: BrunaDomingues Date: Sun, 26 Jul 2026 21:08:12 -0300 Subject: [PATCH 5/6] fix(panel-app): minimize overlap with nickname PR Keep the nickname markup aligned with 4.x and cover birthdate in a dedicated test so merges with #401 stay cleaner. Co-authored-by: Cursor --- .../components/profile-media-header.blade.php | 28 ++++++++++--------- .../tests/Feature/ProfilePageTest.php | 17 +++++++++-- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php index dbfa5e1c..5cca9234 100644 --- a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php +++ b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php @@ -47,7 +47,7 @@ class="absolute top-3 right-3 z-20 rounded-full bg-black/60 p-1.5 text-white tra @endif - {{-- Bottom section: avatar + nickname --}} + {{-- Bottom section: avatar + fields --}}
{{-- Avatar (overlapping cover) --}}
- - +
+
+ + +
diff --git a/app-modules/panel-app/tests/Feature/ProfilePageTest.php b/app-modules/panel-app/tests/Feature/ProfilePageTest.php index 89242cc0..c6e6a965 100644 --- a/app-modules/panel-app/tests/Feature/ProfilePageTest.php +++ b/app-modules/panel-app/tests/Feature/ProfilePageTest.php @@ -76,26 +76,37 @@ livewire(ProfilePage::class) ->set('data.nickname', 'Dan') ->fillForm([ - 'birthdate' => '1996-02-15', 'headline' => 'Backend Developer', 'seniority_level' => 'mid', 'years_experience' => 5, 'about' => 'Dev PHP apaixonado por Laravel', ]) ->call('save') - ->assertHasNoFormErrors() ->assertNotified(); $this->profile->refresh(); expect($this->profile->nickname)->toBe('Dan') - ->and($this->profile->birthdate?->format('Y-m-d'))->toBe('1996-02-15') ->and($this->profile->headline)->toBe('Backend Developer') ->and($this->profile->seniority_level)->toBe(SeniorityLevel::Mid) ->and($this->profile->years_experience)->toBe(5) ->and($this->profile->about)->toBe('Dev PHP apaixonado por Laravel'); }); +test('profile page saves birthdate from date picker', function (): void { + livewire(ProfilePage::class) + ->fillForm([ + 'birthdate' => '1996-02-15', + ]) + ->call('save') + ->assertHasNoFormErrors() + ->assertNotified(); + + $this->profile->refresh(); + + expect($this->profile->birthdate?->format('Y-m-d'))->toBe('1996-02-15'); +}); + test('profile page saves social links from repeater', function (): void { livewire(ProfilePage::class) ->fillForm([ From 69b1e816a9f47b8437ad6e0d11b3581a2a51da32 Mon Sep 17 00:00:00 2001 From: BrunaDomingues Date: Sun, 26 Jul 2026 21:16:20 -0300 Subject: [PATCH 6/6] fix(panel-app): keep birthdate DatePicker beside nickname Render the Filament birthdate picker in the media header next to nickname via a dedicated schema, preserving the original layout. Co-authored-by: Cursor --- .../components/profile-media-header.blade.php | 10 ++-- .../resources/views/pages/profile.blade.php | 3 +- .../panel-app/src/Pages/ProfilePage.php | 51 +++++++++++-------- .../tests/Feature/ProfilePageTest.php | 4 +- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php index 5cca9234..e4fe4c21 100644 --- a/app-modules/panel-app/resources/views/components/profile-media-header.blade.php +++ b/app-modules/panel-app/resources/views/components/profile-media-header.blade.php @@ -2,7 +2,8 @@ 'avatarPreviewUrl' => null, 'coverPreviewUrl' => null, 'initials' => '', - 'name' => '' + 'name' => '', + 'birthdateForm' => null, ])
@@ -99,8 +100,8 @@ class="absolute -top-1 -right-1 z-20 rounded-full bg-red-500 p-1 text-white shad
- {{-- Nickname --}} -
+ {{-- Nickname + Birthdate --}} +
+
+ {{ $birthdateForm }} +
diff --git a/app-modules/panel-app/resources/views/pages/profile.blade.php b/app-modules/panel-app/resources/views/pages/profile.blade.php index e6a41c79..e50e8eff 100644 --- a/app-modules/panel-app/resources/views/pages/profile.blade.php +++ b/app-modules/panel-app/resources/views/pages/profile.blade.php @@ -11,7 +11,8 @@ 'avatarPreviewUrl' => $this->avatarPreviewUrl, 'coverPreviewUrl' => $this->coverPreviewUrl, 'initials' => $this->initials, - 'name' => auth()->user()->name + 'name' => auth()->user()->name, + 'birthdateForm' => $this->birthdateForm, ]) {{ $this->form }} diff --git a/app-modules/panel-app/src/Pages/ProfilePage.php b/app-modules/panel-app/src/Pages/ProfilePage.php index 2d35c0ec..d43d1089 100644 --- a/app-modules/panel-app/src/Pages/ProfilePage.php +++ b/app-modules/panel-app/src/Pages/ProfilePage.php @@ -46,6 +46,7 @@ /** * @property-read Schema $form + * @property-read Schema $birthdateForm */ class ProfilePage extends Page { @@ -72,7 +73,6 @@ public function mount(): void $this->form->fill([ 'nickname' => $profile->nickname, - 'birthdate' => $profile->birthdate?->format('Y-m-d'), 'headline' => $profile->headline, 'seniority_level' => $profile->seniority_level, 'years_experience' => $profile->years_experience, @@ -91,6 +91,34 @@ public function mount(): void $profile->preferences->employmentTypes, ), ]); + + $this->birthdateForm->fill([ + 'birthdate' => $profile->birthdate?->format('Y-m-d'), + ]); + } + + public function birthdateForm(Schema $schema): Schema + { + return $schema + ->components([ + DatePicker::make('birthdate') + ->label(__('panel-app::profile.fields.birthdate')) + ->native(condition: false) + ->displayFormat('d/m/Y') + ->format('Y-m-d') + ->minDate(now()->subYears(120)) + ->maxDate(now()) + ->suffixIcon(Heroicon::Calendar, isInline: true) + ->extraAttributes([ + // Suffix icon sits outside the trigger button; open the panel on icon click. + 'x-on:click' => <<<'JS' + if (! $event.target.closest('.fi-input-wrp-suffix')) return; + if ($event.target.closest('.fi-input-wrp-actions')) return; + $el.querySelector('button.fi-fo-date-time-picker-trigger')?.click(); + JS, + ]), + ]) + ->statePath('data'); } public function form(Schema $schema): Schema @@ -98,26 +126,6 @@ public function form(Schema $schema): Schema return $schema ->components([ Form::make([ - Section::make(__('panel-app::profile.sections.personal')) - ->schema([ - DatePicker::make('birthdate') - ->label(__('panel-app::profile.fields.birthdate')) - ->native(condition: false) - ->displayFormat('d/m/Y') - ->format('Y-m-d') - ->minDate(now()->subYears(120)) - ->maxDate(now()) - ->suffixIcon(Heroicon::Calendar, isInline: true) - ->extraAttributes([ - // Suffix icon sits outside the trigger button; open the panel on icon click. - 'x-on:click' => <<<'JS' - if (! $event.target.closest('.fi-input-wrp-suffix')) return; - if ($event.target.closest('.fi-input-wrp-actions')) return; - $el.querySelector('button.fi-fo-date-time-picker-trigger')?.click(); - JS, - ]), - ]), - Section::make(__('panel-app::profile.sections.professional')) ->schema([ Grid::make(3)->schema([ @@ -390,6 +398,7 @@ public function form(Schema $schema): Schema public function save(): void { + $this->birthdateForm->getState(); $formData = $this->form->getState(); $profile = $this->getRecord(); diff --git a/app-modules/panel-app/tests/Feature/ProfilePageTest.php b/app-modules/panel-app/tests/Feature/ProfilePageTest.php index c6e6a965..c54a358f 100644 --- a/app-modules/panel-app/tests/Feature/ProfilePageTest.php +++ b/app-modules/panel-app/tests/Feature/ProfilePageTest.php @@ -97,9 +97,9 @@ livewire(ProfilePage::class) ->fillForm([ 'birthdate' => '1996-02-15', - ]) + ], 'birthdateForm') ->call('save') - ->assertHasNoFormErrors() + ->assertHasNoFormErrors([], 'birthdateForm') ->assertNotified(); $this->profile->refresh();