Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
122 lines
4.9 KiB
PHP
122 lines
4.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Resources\Members\Schemas;
|
|
|
|
use App\Filament\Support\TranslatableTabs;
|
|
use Filament\Forms\Components\DatePicker;
|
|
use Filament\Forms\Components\FileUpload;
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\Textarea;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Forms\Components\Toggle;
|
|
use Filament\Schemas\Components\Section;
|
|
use Filament\Schemas\Schema;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class MemberForm
|
|
{
|
|
public static function configure(Schema $schema): Schema
|
|
{
|
|
return $schema->components([
|
|
Section::make()
|
|
->columns(2)
|
|
->schema([
|
|
TextInput::make('name')
|
|
->label(__('panel.members.fields.name'))
|
|
->required()
|
|
->maxLength(255)
|
|
->live(onBlur: true)
|
|
->afterStateUpdated(function (?string $state, callable $get, callable $set) {
|
|
if (blank($get('slug'))) {
|
|
$set('slug', Str::slug((string) $state));
|
|
}
|
|
}),
|
|
|
|
TextInput::make('slug')
|
|
->label(__('panel.members.fields.slug'))
|
|
->required()
|
|
->maxLength(255)
|
|
->rules(fn ($record) => [Rule::unique('members', 'slug')->ignore($record?->id)]),
|
|
|
|
FileUpload::make('avatar')
|
|
->label(__('panel.members.fields.avatar'))
|
|
->image()
|
|
->avatar()
|
|
// Explicit: the default disk is private, and the
|
|
// frontend runs on another host.
|
|
->disk(config('media.disk'))
|
|
->directory('members')
|
|
->imageEditor()
|
|
// A portrait is described by the person's name, so
|
|
// there is no alt field here to fill in wrong.
|
|
->helperText(__('panel.members.fields.avatar_hint')),
|
|
|
|
// The link that makes commit attribution and the git
|
|
// integration line up with a real person.
|
|
TextInput::make('github_username')
|
|
->label(__('panel.members.fields.github_username'))
|
|
->prefix('github.com/')
|
|
->maxLength(120),
|
|
|
|
Select::make('user_id')
|
|
->label(__('panel.members.fields.user'))
|
|
->relationship('user', 'name')
|
|
->searchable()
|
|
->preload()
|
|
->helperText(__('panel.members.fields.user_hint')),
|
|
|
|
Select::make('technologies')
|
|
->label(__('panel.members.fields.technologies'))
|
|
->relationship('technologies', 'name')
|
|
->multiple()
|
|
->preload()
|
|
->searchable(),
|
|
]),
|
|
|
|
Section::make(__('panel.members.sections.profile'))
|
|
->description(__('panel.members.sections.profile_hint'))
|
|
->schema([
|
|
TranslatableTabs::make(fn (string $locale, bool $isDefault) => [
|
|
TextInput::make("headline.{$locale}")
|
|
->label(__('panel.members.fields.headline'))
|
|
->maxLength(255)
|
|
->columnSpanFull(),
|
|
|
|
Textarea::make("bio.{$locale}")
|
|
->label(__('panel.members.fields.bio'))
|
|
->rows(5)
|
|
->columnSpanFull(),
|
|
]),
|
|
]),
|
|
|
|
Section::make(__('panel.members.sections.membership'))
|
|
->columns(3)
|
|
->schema([
|
|
Toggle::make('is_public')
|
|
->label(__('panel.members.fields.is_public'))
|
|
->default(true),
|
|
|
|
Toggle::make('is_founder')
|
|
->label(__('panel.members.fields.is_founder')),
|
|
|
|
TextInput::make('position')
|
|
->label(__('panel.members.fields.position'))
|
|
->numeric()
|
|
->default(0),
|
|
|
|
DatePicker::make('joined_at')
|
|
->label(__('panel.members.fields.joined_at')),
|
|
|
|
// Leaving hides them from the current roster without
|
|
// erasing the work they did.
|
|
DatePicker::make('left_at')
|
|
->label(__('panel.members.fields.left_at'))
|
|
->helperText(__('panel.members.fields.left_at_hint')),
|
|
]),
|
|
]);
|
|
}
|
|
}
|