-
Notifications
You must be signed in to change notification settings - Fork 30
feat(panel-admin): profile tab on UserResource #256 #293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Hadzab
wants to merge
5
commits into
4.x
Choose a base branch
from
feat/256-admin-panel-profile-tab
base: 4.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1978b4f
feat(panel-admin): profile tab on UserResource #256
Hadzab 3167810
feat(panel-admin): profile tab on UserResource #256
Hadzab 4fdf956
fix: add table columns, persist account fields, fix social links edge…
Hadzab 43935a9
fix: resolve PHPStan errors and CodeRabbit suggestions
Hadzab 704642d
fix: add table filters for created_at and tenant
Hadzab File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
app-modules/panel-admin/src/Filament/Resources/Users/Pages/CreateUser.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace He4rt\PanelAdmin\Filament\Resources\Users\Pages; | ||
|
|
||
| use Filament\Resources\Pages\CreateRecord; | ||
| use He4rt\PanelAdmin\Filament\Resources\Users\UserResource; | ||
|
|
||
| class CreateUser extends CreateRecord | ||
| { | ||
| protected static string $resource = UserResource::class; | ||
| } |
142 changes: 142 additions & 0 deletions
142
app-modules/panel-admin/src/Filament/Resources/Users/Pages/EditUser.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace He4rt\PanelAdmin\Filament\Resources\Users\Pages; | ||
|
|
||
| use Filament\Facades\Filament; | ||
| use Filament\Notifications\Notification; | ||
| use Filament\Resources\Pages\EditRecord; | ||
| use He4rt\Identity\User\Models\User; | ||
| use He4rt\PanelAdmin\Filament\Resources\Users\UserResource; | ||
| use He4rt\Profile\Actions\ToggleAvailability; | ||
| use He4rt\Profile\Actions\UpsertProfile; | ||
| use He4rt\Profile\DTOs\UpsertProfileDTO; | ||
| use He4rt\Profile\Enums\SocialPlatform; | ||
| use He4rt\Profile\Enums\StartAvailability; | ||
| use He4rt\Profile\Models\Profile; | ||
| use Illuminate\Database\Eloquent\Model; | ||
| use Illuminate\Validation\ValidationException; | ||
|
|
||
| class EditUser extends EditRecord | ||
| { | ||
| protected static string $resource = UserResource::class; | ||
|
|
||
| protected function mutateFormDataBeforeFill(array $data): array | ||
| { | ||
| $profile = $this->getProfile(); | ||
|
|
||
| $data['profile'] = [ | ||
| 'nickname' => $profile->nickname, | ||
| 'birthdate' => $profile->birthdate?->format('Y-m-d'), | ||
| 'headline' => $profile->headline, | ||
| 'seniority_level' => $profile->seniority_level, | ||
| 'years_experience' => $profile->years_experience, | ||
| 'about' => $profile->about, | ||
| 'available_for_proposals' => $profile->available_for_proposals, | ||
| 'start_availability' => $profile->start_availability, | ||
| 'social_links' => $this->socialLinksToRepeater($profile->social_links), | ||
| ]; | ||
|
|
||
| return $data; | ||
| } | ||
|
|
||
| protected function handleRecordUpdate(Model $record, array $data): Model | ||
| { | ||
| $profile = $this->getProfile(); | ||
| $profileData = $data['profile'] ?? []; | ||
|
|
||
| $socialLinks = $this->repeaterToSocialLinks($profileData['social_links'] ?? []); | ||
|
|
||
| $dto = UpsertProfileDTO::fromArray([ | ||
| 'nickname' => $profileData['nickname'] ?? null, | ||
| 'birthdate' => $profileData['birthdate'] ?? null, | ||
| 'about' => $profileData['about'] ?? null, | ||
| 'headline' => $profileData['headline'] ?? null, | ||
| 'seniority_level' => $profileData['seniority_level'] ?? null, | ||
| 'years_experience' => $profileData['years_experience'] ?? null, | ||
| 'social_links' => $socialLinks, | ||
| ]); | ||
|
|
||
| resolve(UpsertProfile::class)->handle($profile, $dto); | ||
|
|
||
| $available = (bool) ($profileData['available_for_proposals'] ?? false); | ||
| $rawStartAvailability = $profileData['start_availability'] ?? null; | ||
| $startAvailability = match (true) { | ||
| $rawStartAvailability instanceof StartAvailability => $rawStartAvailability, | ||
| is_string($rawStartAvailability) => StartAvailability::from($rawStartAvailability), | ||
| $available => StartAvailability::Negotiable, | ||
| default => null, | ||
| }; | ||
|
|
||
| resolve(ToggleAvailability::class)->handle($profile, $available, $startAvailability); | ||
|
|
||
| Notification::make() | ||
| ->success() | ||
| ->title('Perfil atualizado com sucesso!') | ||
| ->send(); | ||
|
|
||
| /** @var User $record */ | ||
| $record->update([ | ||
| 'name' => $data['name'] ?? $record->name, | ||
| 'email' => $data['email'] ?? $record->email, | ||
| ]); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| return $record; | ||
|
Hadzab marked this conversation as resolved.
|
||
| } | ||
|
|
||
| private function getProfile(): Profile | ||
| { | ||
| $tenantId = Filament::getTenant()?->getKey(); | ||
| abort_unless($tenantId, 403); | ||
|
|
||
| return Profile::query()->firstOrCreate([ | ||
| 'user_id' => $this->record->getKey(), | ||
| 'tenant_id' => $tenantId, | ||
| ]); | ||
| } | ||
|
|
||
| /** | ||
| * @param array<string, string>|null $socialLinks | ||
| * @return list<array{platform: string, handle: string}> | ||
| */ | ||
| private function socialLinksToRepeater(?array $socialLinks): array | ||
| { | ||
| if ($socialLinks === null) { | ||
| return []; | ||
| } | ||
|
|
||
| return collect($socialLinks) | ||
| ->map(fn ($handle, $platform) => ['platform' => $platform, 'handle' => $handle]) | ||
| ->values() | ||
| ->all(); | ||
| } | ||
|
|
||
| /** | ||
| * @param array<int|string, array<string, mixed>> $repeaterData | ||
| * @return array<string, string> | ||
| */ | ||
| private function repeaterToSocialLinks(array $repeaterData): array | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| { | ||
| $links = []; | ||
|
|
||
| foreach ($repeaterData as $item) { | ||
| $platform = $item['platform'] ?? null; | ||
| $handle = $item['handle'] ?? null; | ||
|
|
||
| if (filled($platform) && filled($handle)) { | ||
| $key = $platform instanceof SocialPlatform ? $platform->value : (string) $platform; | ||
|
|
||
| if (isset($links[$key])) { | ||
| throw ValidationException::withMessages([ | ||
| 'profile.social_links' => ['Plataforma duplicada: '.$key], | ||
| ]); | ||
| } | ||
|
|
||
| $links[$key] = (string) $handle; | ||
| } | ||
|
Hadzab marked this conversation as resolved.
|
||
| } | ||
|
|
||
| return $links; | ||
| } | ||
| } | ||
21 changes: 21 additions & 0 deletions
21
app-modules/panel-admin/src/Filament/Resources/Users/Pages/ListUsers.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace He4rt\PanelAdmin\Filament\Resources\Users\Pages; | ||
|
|
||
| use Filament\Actions\CreateAction; | ||
| use Filament\Resources\Pages\ListRecords; | ||
| use He4rt\PanelAdmin\Filament\Resources\Users\UserResource; | ||
|
|
||
| class ListUsers extends ListRecords | ||
| { | ||
| protected static string $resource = UserResource::class; | ||
|
|
||
| protected function getHeaderActions(): array | ||
| { | ||
| return [ | ||
| CreateAction::make(), | ||
| ]; | ||
| } | ||
| } |
127 changes: 127 additions & 0 deletions
127
app-modules/panel-admin/src/Filament/Resources/Users/Schemas/UserForm.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace He4rt\PanelAdmin\Filament\Resources\Users\Schemas; | ||
|
|
||
| use Filament\Forms\Components\DatePicker; | ||
| use Filament\Forms\Components\Repeater; | ||
| use Filament\Forms\Components\Select; | ||
| use Filament\Forms\Components\Textarea; | ||
| use Filament\Forms\Components\TextInput; | ||
| use Filament\Forms\Components\Toggle; | ||
| use Filament\Schemas\Components\Grid; | ||
| use Filament\Schemas\Components\Section; | ||
| use Filament\Schemas\Components\Tabs; | ||
| use Filament\Schemas\Components\Tabs\Tab; | ||
| use Filament\Schemas\Components\Utilities\Get; | ||
| use Filament\Schemas\Schema; | ||
| use He4rt\Profile\Enums\SeniorityLevel; | ||
| use He4rt\Profile\Enums\SocialPlatform; | ||
| use He4rt\Profile\Enums\StartAvailability; | ||
|
|
||
| class UserForm | ||
| { | ||
| public static function configure(Schema $schema): Schema | ||
| { | ||
| return $schema | ||
| ->components([ | ||
| Tabs::make() | ||
| ->tabs([ | ||
| Tab::make('Conta') | ||
| ->schema([ | ||
| TextInput::make('name') | ||
| ->label('Nome') | ||
| ->required(), | ||
|
|
||
| TextInput::make('email') | ||
| ->label('Email') | ||
| ->email() | ||
| ->required(), | ||
| ]), | ||
|
|
||
| Tab::make('Profile') | ||
| ->schema([ | ||
| Section::make('Dados Pessoais') | ||
| ->schema([ | ||
| Grid::make(2)->schema([ | ||
| TextInput::make('profile.nickname') | ||
| ->label('Apelido') | ||
| ->maxLength(100) | ||
| ->columnSpan(1), | ||
|
|
||
| DatePicker::make('profile.birthdate') | ||
| ->label('Data de nascimento') | ||
| ->columnSpan(1), | ||
| ]), | ||
| ]), | ||
|
|
||
| Section::make('Dados Profissionais') | ||
| ->schema([ | ||
| Grid::make(3)->schema([ | ||
| TextInput::make('profile.headline') | ||
| ->label('Título') | ||
| ->maxLength(100) | ||
| ->columnSpan(1), | ||
|
|
||
| Select::make('profile.seniority_level') | ||
| ->label('Senioridade') | ||
| ->options(SeniorityLevel::class) | ||
| ->columnSpan(1), | ||
|
|
||
| TextInput::make('profile.years_experience') | ||
| ->label('Anos de experiência') | ||
| ->numeric() | ||
| ->minValue(0) | ||
| ->maxValue(50) | ||
| ->columnSpan(1), | ||
|
|
||
| Textarea::make('profile.about') | ||
| ->label('Bio') | ||
| ->maxLength(500) | ||
| ->rows(4) | ||
| ->columnSpanFull(), | ||
| ]), | ||
| ]), | ||
|
|
||
| Section::make('Links Sociais') | ||
| ->schema([ | ||
| Repeater::make('profile.social_links') | ||
| ->label('') | ||
| ->schema([ | ||
| Grid::make(2)->schema([ | ||
| Select::make('platform') | ||
| ->label('Plataforma') | ||
| ->options(SocialPlatform::class) | ||
| ->required() | ||
| ->columnSpan(1), | ||
|
|
||
| TextInput::make('handle') | ||
| ->label('Handle') | ||
| ->required() | ||
| ->columnSpan(1), | ||
| ]), | ||
| ]) | ||
| ->defaultItems(0) | ||
| ->reorderable(false) | ||
| ->columnSpanFull(), | ||
| ]), | ||
|
|
||
| Section::make('Disponibilidade') | ||
| ->schema([ | ||
| Toggle::make('profile.available_for_proposals') | ||
| ->label('Disponível para propostas') | ||
| ->live(), | ||
|
|
||
| Select::make('profile.start_availability') | ||
| ->label('Disponibilidade de início') | ||
| ->options(StartAvailability::class) | ||
| ->live() | ||
| ->visible(fn (Get $get): bool => (bool) $get('profile.available_for_proposals')), | ||
| ]), | ||
| ]), | ||
| ]) | ||
| ->columnSpanFull(), | ||
| ]); | ||
| } | ||
| } |
73 changes: 73 additions & 0 deletions
73
app-modules/panel-admin/src/Filament/Resources/Users/UserResource.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace He4rt\PanelAdmin\Filament\Resources\Users; | ||
|
|
||
| use BackedEnum; | ||
| use Filament\Resources\Resource; | ||
| use Filament\Schemas\Schema; | ||
| use Filament\Support\Icons\Heroicon; | ||
| use Filament\Tables\Columns\TextColumn; | ||
| use Filament\Tables\Filters\Filter; | ||
| use Filament\Tables\Filters\SelectFilter; | ||
| use Filament\Tables\Table; | ||
| use He4rt\Identity\User\Models\User; | ||
| use He4rt\PanelAdmin\Filament\Resources\Users\Pages\CreateUser; | ||
| use He4rt\PanelAdmin\Filament\Resources\Users\Pages\EditUser; | ||
| use He4rt\PanelAdmin\Filament\Resources\Users\Pages\ListUsers; | ||
| use He4rt\PanelAdmin\Filament\Resources\Users\Schemas\UserForm; | ||
| use Illuminate\Database\Eloquent\Builder; | ||
|
|
||
| class UserResource extends Resource | ||
| { | ||
| protected static ?string $model = User::class; | ||
|
|
||
| protected static ?string $slug = 'users'; | ||
|
|
||
| protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedUsers; | ||
|
|
||
| public static function form(Schema $schema): Schema | ||
| { | ||
| return UserForm::configure($schema); | ||
| } | ||
|
|
||
| public static function table(Table $table): Table | ||
| { | ||
| return $table | ||
| ->columns([ | ||
| TextColumn::make('name') | ||
| ->label('Nome') | ||
| ->searchable() | ||
| ->sortable(), | ||
|
|
||
| TextColumn::make('email') | ||
| ->label('Email') | ||
| ->searchable() | ||
| ->sortable(), | ||
|
|
||
| TextColumn::make('created_at') | ||
| ->label('Criado em') | ||
| ->dateTime('d/m/Y') | ||
| ->sortable(), | ||
| ]) | ||
| ->filters([ | ||
| Filter::make('created_at') | ||
| ->label('Criado este mês') | ||
| ->query(fn (Builder $query) => $query->whereMonth('created_at', now()->month)), | ||
|
|
||
| SelectFilter::make('tenant') | ||
| ->label('Tenant') | ||
| ->relationship('tenants', 'name'), | ||
| ]); | ||
| } | ||
|
Hadzab marked this conversation as resolved.
|
||
|
|
||
| public static function getPages(): array | ||
| { | ||
| return [ | ||
| 'index' => ListUsers::route('/'), | ||
| 'create' => CreateUser::route('/create'), | ||
| 'edit' => EditUser::route('/{record}/edit'), | ||
| ]; | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.