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 66d6d235..c55e5e5f 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
@@ -127,11 +127,15 @@ class="absolute inset-0 z-30 flex items-center justify-center rounded-full bg-bl
+ @error('nickname')
+
{{ $message }}
+ @enderror
-
+
\ No newline at end of file
diff --git a/app-modules/panel-app/resources/views/components/profile-preview-card.blade.php b/app-modules/panel-app/resources/views/components/profile-preview-card.blade.php
index 5386dac5..65b125c0 100644
--- a/app-modules/panel-app/resources/views/components/profile-preview-card.blade.php
+++ b/app-modules/panel-app/resources/views/components/profile-preview-card.blade.php
@@ -8,9 +8,9 @@
])
@php
- $name = $user?->name ?? '';
$username = $user?->username ?? '';
$nickname = $data['nickname'] ?? null;
+ $name = ($nickname ?: null) ?? $user?->name ?? $username;
$headline = $data['headline'] ?? null;
$about = $data['about'] ?? null;
$yearsExperience = $data['years_experience'] ?? null;
@@ -266,4 +266,4 @@ class="inline-block rounded-full border border-gray-200 bg-gray-50 px-2.5 py-0.5
Esse card aparece na listagem de membros e no seu perfil público.
-
+
\ No newline at end of file
diff --git a/app-modules/panel-app/src/Pages/ProfilePage.php b/app-modules/panel-app/src/Pages/ProfilePage.php
index d007d531..fad37c5d 100644
--- a/app-modules/panel-app/src/Pages/ProfilePage.php
+++ b/app-modules/panel-app/src/Pages/ProfilePage.php
@@ -38,6 +38,7 @@
use He4rt\Profile\Models\Profile;
use He4rt\Profile\Models\Skill;
use Illuminate\Support\Str;
+use Illuminate\Validation\ValidationException;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Validate;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
@@ -61,6 +62,8 @@ class ProfilePage extends Page
#[Validate(rule: 'nullable|image|mimes:jpg,jpeg,png,webp|max:4096')]
public $coverUpload;
+ public ?string $nicknameInput = null;
+
protected static string|null|BackedEnum $navigationIcon = 'heroicon-o-user-circle';
protected static ?string $title = 'Profile';
@@ -98,6 +101,8 @@ public function mount(): void
$profile->preferences->employmentTypes,
),
]);
+
+ $this->nicknameInput = $profile->nickname;
}
public function form(Schema $schema): Schema
@@ -374,13 +379,15 @@ public function form(Schema $schema): Schema
public function save(): void
{
+ $this->resetErrorBag('nickname');
+
$formData = $this->form->getState();
$profile = $this->getRecord();
$socialLinks = $this->repeaterToSocialLinks($formData['social_links'] ?? []);
$dto = UpsertProfileDTO::fromArray([
- 'nickname' => $this->data['nickname'] ?? null,
+ 'nickname' => mb_trim($this->nicknameInput ?? ''),
'birthdate' => $this->data['birthdate'] ?? null,
'about' => $formData['about'] ?? null,
'headline' => $formData['headline'] ?? null,
@@ -397,7 +404,16 @@ public function save(): void
],
]);
- resolve(UpsertProfile::class)->handle($profile, $dto);
+ try {
+ resolve(UpsertProfile::class)->handle($profile, $dto);
+ } catch (ValidationException $validationException) {
+ $this->addError('nickname', $validationException->validator->errors()->first('nickname'));
+ $this->dispatch('scroll-to-nickname');
+
+ return;
+ }
+
+ $this->data['nickname'] = mb_trim($this->nicknameInput ?? '') ?: null;
$available = (bool) ($formData['available_for_proposals'] ?? false);
$rawStartAvailability = $formData['start_availability'] ?? null;
diff --git a/app-modules/panel-app/tests/Feature/ProfilePageTest.php b/app-modules/panel-app/tests/Feature/ProfilePageTest.php
index 60ff3599..2421afaa 100644
--- a/app-modules/panel-app/tests/Feature/ProfilePageTest.php
+++ b/app-modules/panel-app/tests/Feature/ProfilePageTest.php
@@ -75,7 +75,7 @@
test('profile page saves all fields', function (): void {
livewire(ProfilePage::class)
- ->set('data.nickname', 'Dan')
+ ->set('nicknameInput', 'Dan')
->fillForm([
'headline' => 'Backend Developer',
'seniority_level' => 'mid',
diff --git a/app-modules/profile/src/Actions/UpsertProfile.php b/app-modules/profile/src/Actions/UpsertProfile.php
index 2dd859bf..5cea786b 100644
--- a/app-modules/profile/src/Actions/UpsertProfile.php
+++ b/app-modules/profile/src/Actions/UpsertProfile.php
@@ -21,7 +21,7 @@ public function handle(Profile $profile, UpsertProfileDTO $dto): Profile
$attributes = [];
if ($dto->nickname !== null) {
- $attributes['nickname'] = $dto->nickname;
+ $attributes['nickname'] = $dto->nickname === '' ? null : $dto->nickname;
}
if ($dto->birthdate instanceof CarbonInterface) {
@@ -79,8 +79,14 @@ private function validate(UpsertProfileDTO $dto): void
$errors['headline'] = [__('validation.max.string', ['attribute' => 'headline', 'max' => 100])];
}
- if ($dto->nickname !== null && mb_strlen($dto->nickname) > 100) {
- $errors['nickname'] = [__('validation.max.string', ['attribute' => 'nickname', 'max' => 100])];
+ if ($dto->nickname !== null && $dto->nickname !== '') {
+ if (mb_strlen($dto->nickname) > 100) {
+ $errors['nickname'] = ['O apelido deve ter no máximo 100 caracteres.'];
+ } elseif (!preg_match("/^[\p{L}\p{M}\p{N}\s\-']+$/u", $dto->nickname)) {
+ $errors['nickname'] = ['Apenas letras, números, espaços, hífens e apóstrofos são permitidos.'];
+ } elseif (!preg_match('/[\p{L}]{2,}/u', $dto->nickname)) {
+ $errors['nickname'] = ['O apelido deve conter pelo menos 2 letras juntas.'];
+ }
}
if ($dto->yearsExperience !== null && ($dto->yearsExperience < 0 || $dto->yearsExperience > 50)) {