Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
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,
]);
Comment thread
Hadzab marked this conversation as resolved.

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,
]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return $record;
Comment thread
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
Comment thread
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;
}
Comment thread
Hadzab marked this conversation as resolved.
}

return $links;
}
}
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(),
];
}
}
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(),
]);
}
}
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'),
]);
}
Comment thread
Hadzab marked this conversation as resolved.

public static function getPages(): array
{
return [
'index' => ListUsers::route('/'),
'create' => CreateUser::route('/create'),
'edit' => EditUser::route('/{record}/edit'),
];
}
}
Loading