diff --git a/packages/admin/README.md b/packages/admin/README.md index d48aaf62a3..6827a25ba9 100644 --- a/packages/admin/README.md +++ b/packages/admin/README.md @@ -13,7 +13,7 @@ See the docs at https://lunar-panel.vercel.app/ - [ ] Tax Zone types are "country", "states", "postcodes" -> would prefer it to be "countries" so it's consistent - [ ] `ListField` FieldType shouldn't really have "Field" in its name -> change to simply "List" - [ ] Sometimes we use "Enabled" other times "Active". Do we want to consider consistency here also? -- [ ] Staff "firstname" "lastname" I think should have underscores, e.g. "first_name" +- [x] Staff "firstname" "lastname" I think should have underscores, e.g. "first_name" - [x] How to allow devs to extend Lunar's forms and tables - [x] How to allow devs to overide validation rules - [x] Allow devs to extend by adding their own pages/resources diff --git a/packages/admin/database/factories/StaffFactory.php b/packages/admin/database/factories/StaffFactory.php index 0b50dfc9ea..3300af96ac 100644 --- a/packages/admin/database/factories/StaffFactory.php +++ b/packages/admin/database/factories/StaffFactory.php @@ -20,8 +20,8 @@ class StaffFactory extends Factory public function definition(): array { return [ - 'firstname' => $this->faker->firstName(), - 'lastname' => $this->faker->lastName(), + 'first_name' => $this->faker->firstName(), + 'last_name' => $this->faker->lastName(), 'admin' => $this->faker->boolean(5), 'email' => $this->faker->unique()->safeEmail(), 'email_verified_at' => now(), diff --git a/packages/admin/database/migrations/2024_11_25_110000_rename_firstname_column_on_staff_table.php b/packages/admin/database/migrations/2024_11_25_110000_rename_firstname_column_on_staff_table.php new file mode 100644 index 0000000000..357cf0c28d --- /dev/null +++ b/packages/admin/database/migrations/2024_11_25_110000_rename_firstname_column_on_staff_table.php @@ -0,0 +1,22 @@ +prefix.'staff', function (Blueprint $table) { + $table->renameColumn('firstname', 'first_name'); + }); + } + + public function down(): void + { + Schema::table($this->prefix.'staff', function (Blueprint $table) { + $table->renameColumn('first_name', 'firstname'); + }); + } +}; diff --git a/packages/admin/database/migrations/2024_11_25_110001_rename_lastname_column_on_staff_table.php b/packages/admin/database/migrations/2024_11_25_110001_rename_lastname_column_on_staff_table.php new file mode 100644 index 0000000000..98be1ed52e --- /dev/null +++ b/packages/admin/database/migrations/2024_11_25_110001_rename_lastname_column_on_staff_table.php @@ -0,0 +1,22 @@ +prefix.'staff', function (Blueprint $table) { + $table->renameColumn('lastname', 'last_name'); + }); + } + + public function down(): void + { + Schema::table($this->prefix.'staff', function (Blueprint $table) { + $table->renameColumn('last_name', 'lastname'); + }); + } +}; diff --git a/packages/admin/resources/lang/en/staff.php b/packages/admin/resources/lang/en/staff.php index 5679833c40..d5b6e43a09 100644 --- a/packages/admin/resources/lang/en/staff.php +++ b/packages/admin/resources/lang/en/staff.php @@ -7,10 +7,10 @@ 'plural_label' => 'Staff', 'table' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'First Name', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Last Name', ], 'email' => [ @@ -22,10 +22,10 @@ ], 'form' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'First Name', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Last Name', ], 'email' => [ diff --git a/packages/admin/resources/lang/es/staff.php b/packages/admin/resources/lang/es/staff.php index bb244d3cc8..b1029457e7 100644 --- a/packages/admin/resources/lang/es/staff.php +++ b/packages/admin/resources/lang/es/staff.php @@ -7,10 +7,10 @@ 'plural_label' => 'Personal', 'table' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'Nombre', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Apellido', ], 'email' => [ @@ -22,10 +22,10 @@ ], 'form' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'Nombre', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Apellido', ], 'email' => [ diff --git a/packages/admin/resources/lang/fr/staff.php b/packages/admin/resources/lang/fr/staff.php index 14d8ae4feb..a163cba370 100644 --- a/packages/admin/resources/lang/fr/staff.php +++ b/packages/admin/resources/lang/fr/staff.php @@ -7,10 +7,10 @@ 'plural_label' => 'Personnel', 'table' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'Prénom', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Nom de famille', ], 'email' => [ @@ -22,10 +22,10 @@ ], 'form' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'Prénom', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Nom de famille', ], 'email' => [ diff --git a/packages/admin/resources/lang/nl/staff.php b/packages/admin/resources/lang/nl/staff.php index bf9add60b6..178a965d2f 100644 --- a/packages/admin/resources/lang/nl/staff.php +++ b/packages/admin/resources/lang/nl/staff.php @@ -7,10 +7,10 @@ 'plural_label' => 'Personeel', 'table' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'Voornaam', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Achternaam', ], 'email' => [ @@ -22,10 +22,10 @@ ], 'form' => [ - 'firstname' => [ + 'first_name' => [ 'label' => 'Voornaam', ], - 'lastname' => [ + 'last_name' => [ 'label' => 'Achternaam', ], 'email' => [ diff --git a/packages/admin/src/Console/Commands/MakeLunarAdminCommand.php b/packages/admin/src/Console/Commands/MakeLunarAdminCommand.php index 0b48d126fc..7e8bd2cba7 100644 --- a/packages/admin/src/Console/Commands/MakeLunarAdminCommand.php +++ b/packages/admin/src/Console/Commands/MakeLunarAdminCommand.php @@ -32,12 +32,12 @@ class MakeLunarAdminCommand extends Command protected function getUserData(): array { return [ - 'firstname' => $this->options['firstname'] ?? text( + 'first_name' => $this->options['firstname'] ?? text( label: 'First Name', required: true, ), - 'lastname' => $this->options['lastname'] ?? text( + 'last_name' => $this->options['lastname'] ?? text( label: 'Last Name', required: true, ), diff --git a/packages/admin/src/Filament/Resources/StaffResource.php b/packages/admin/src/Filament/Resources/StaffResource.php index f383eade58..019744072f 100644 --- a/packages/admin/src/Filament/Resources/StaffResource.php +++ b/packages/admin/src/Filament/Resources/StaffResource.php @@ -63,8 +63,8 @@ protected static function getMainFormComponents(): array protected static function getFirstNameFormComponent(): Component { - return Forms\Components\TextInput::make('firstname') - ->label(__('lunarpanel::staff.form.firstname.label')) + return Forms\Components\TextInput::make('first_name') + ->label(__('lunarpanel::staff.form.first_name.label')) ->required() ->maxLength(255) ->autofocus(); @@ -72,8 +72,8 @@ protected static function getFirstNameFormComponent(): Component protected static function getLastNameFormComponent(): Component { - return Forms\Components\TextInput::make('lastname') - ->label(__('lunarpanel::staff.form.lastname.label')) + return Forms\Components\TextInput::make('last_name') + ->label(__('lunarpanel::staff.form.last_name.label')) ->required() ->maxLength(255) ->autofocus(); @@ -169,10 +169,10 @@ public static function getDefaultTable(Table $table): Table { return $table ->columns([ - Tables\Columns\TextColumn::make('firstname') - ->label(__('lunarpanel::staff.table.firstname.label')), - Tables\Columns\TextColumn::make('lastname') - ->label(__('lunarpanel::staff.table.lastname.label')), + Tables\Columns\TextColumn::make('first_name') + ->label(__('lunarpanel::staff.table.first_name.label')), + Tables\Columns\TextColumn::make('last_name') + ->label(__('lunarpanel::staff.table.last_name.label')), Tables\Columns\TextColumn::make('email') ->label(__('lunarpanel::staff.table.email.label')), Tables\Columns\TextColumn::make('admin') diff --git a/packages/admin/src/Models/Staff.php b/packages/admin/src/Models/Staff.php index 1ddf25c993..28689d5170 100644 --- a/packages/admin/src/Models/Staff.php +++ b/packages/admin/src/Models/Staff.php @@ -5,6 +5,8 @@ use Filament\Models\Contracts\FilamentUser; use Filament\Models\Contracts\HasName; use Filament\Panel; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; @@ -12,6 +14,22 @@ use Lunar\Admin\Database\Factories\StaffFactory; use Spatie\Permission\Traits\HasRoles; +/** + * @property int $id + * @property bool $admin + * @property string $first_name + * @property string $last_name + * @property string $full_name + * @property string $email + * @property string $password + * @property string $remember_token + * @property ?\Illuminate\Support\Carbon $email_verified_at + * @property ?\Illuminate\Support\Carbon $created_at + * @property ?\Illuminate\Support\Carbon $updated_at + * @property ?\Illuminate\Support\Carbon $deleted_at + * + * @method static \Illuminate\Database\Eloquent\Builder search(?string $terms) + */ class Staff extends Authenticatable implements FilamentUser, HasName { use HasFactory; @@ -19,59 +37,54 @@ class Staff extends Authenticatable implements FilamentUser, HasName use Notifiable; use SoftDeletes; - /** - * Return a new factory instance for the model. - */ - protected static function newFactory() - { - return StaffFactory::new(); - } + protected $guard_name = 'staff'; - /** - * The attributes that are mass assignable. - * - * @var array - */ protected $fillable = [ - 'firstname', - 'lastname', + 'first_name', + 'last_name', 'admin', 'email', 'password', ]; - protected $guard_name = 'staff'; + protected $casts = [ + 'admin' => 'bool', + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; - /** - * The attributes that should be hidden for arrays. - * - * @var array - */ protected $hidden = [ 'password', 'remember_token', ]; - /** - * The attributes that should be cast to native types. - * - * @var array - */ - protected $casts = [ - 'email_verified_at' => 'datetime', - 'password' => 'hashed', + protected $appends = [ + 'full_name', ]; - /** - * Append attributes to the model. - * - * @var array - */ - protected $appends = ['fullName']; + protected function firstname(): Attribute + { + return Attribute::make( + get: fn (mixed $value, array $attributes) => $attributes['first_name'], + set: fn (string $value) => ['first_name' => $value], + ); + } + + protected function lastname(): Attribute + { + return Attribute::make( + get: fn (mixed $value, array $attributes) => $attributes['last_name'], + set: fn (string $value) => ['last_name' => $value], + ); + } + + protected function fullName(): Attribute + { + return Attribute::get( + fn (): string => "{$this->first_name} {$this->last_name}", + ); + } - /** - * Create a new instance of the Model. - */ public function __construct(array $attributes = []) { parent::__construct($attributes); @@ -83,45 +96,20 @@ public function __construct(array $attributes = []) } } - /** - * Retrieve the model for a bound value. - * - * Currently Livewire doesn't support route bindings for - * soft deleted models so we need to rewire it here. - * - * @param mixed $value - * @param string|null $field - * @return \Illuminate\Database\Eloquent\Model|null - */ - public function resolveRouteBinding($value, $field = null) + protected static function newFactory(): StaffFactory { - return $this->resolveSoftDeletableRouteBinding($value, $field); + return StaffFactory::new(); } - /** - * Apply the basic search scope to a given Eloquent query builder. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param string $term - * @return void - */ - public function scopeSearch($query, $term) + public function scopeSearch(Builder $query, ?string $terms): void { - if ($term) { - $parts = explode(' ', $term); - - foreach ($parts as $part) { - $query->whereAny(['email', 'firstname', 'lastname'], 'LIKE', "%$part%"); - } + if (! $terms) { + return; } - } - /** - * Get staff member's full name. - */ - public function getFullNameAttribute(): string - { - return $this->firstname.' '.$this->lastname; + foreach (explode(' ', $terms) as $term) { + $query->whereAny(['email', 'first_name', 'last_name'], 'LIKE', "%{$term}%"); + } } public function canAccessPanel(Panel $panel): bool @@ -131,6 +119,6 @@ public function canAccessPanel(Panel $panel): bool public function getFilamentName(): string { - return $this->fullName; + return $this->full_name; } } diff --git a/tests/admin/Feature/Filament/Resources/StaffResource/Pages/CreateStaffTest.php b/tests/admin/Feature/Filament/Resources/StaffResource/Pages/CreateStaffTest.php index 975a498e3e..838364731a 100644 --- a/tests/admin/Feature/Filament/Resources/StaffResource/Pages/CreateStaffTest.php +++ b/tests/admin/Feature/Filament/Resources/StaffResource/Pages/CreateStaffTest.php @@ -22,8 +22,8 @@ $staff->assignRole('staff'); $formData = [ - 'firstname' => $staff->firstname, - 'lastname' => $staff->lastname, + 'first_name' => $staff->first_name, + 'last_name' => $staff->last_name, 'email' => 'test@example.com', 'password' => 'password', ]; diff --git a/tests/admin/Feature/Filament/Resources/StaffResource/Pages/EditStaffTest.php b/tests/admin/Feature/Filament/Resources/StaffResource/Pages/EditStaffTest.php index 59c5c0df3d..d06e1623e2 100644 --- a/tests/admin/Feature/Filament/Resources/StaffResource/Pages/EditStaffTest.php +++ b/tests/admin/Feature/Filament/Resources/StaffResource/Pages/EditStaffTest.php @@ -24,8 +24,8 @@ 'record' => $staff->getRouteKey(), ]) ->assertFormSet([ - 'firstname' => $staff->firstname, - 'lastname' => $staff->lastname, + 'first_name' => $staff->first_name, + 'last_name' => $staff->last_name, 'email' => $staff->email, ]); }); @@ -39,16 +39,16 @@ 'record' => $staff->getRouteKey(), ]) ->fillForm([ - 'firstname' => $newData->firstname, - 'lastname' => $newData->lastname, + 'first_name' => $newData->first_name, + 'last_name' => $newData->last_name, 'email' => $newData->email, ]) ->call('save') ->assertHasNoFormErrors(); expect($staff->refresh()) - ->firstname->toBe($newData->firstname) - ->lastname->toBe($newData->lastname) + ->first_name->toBe($newData->first_name) + ->last_name->toBe($newData->last_name) ->email->toBe($newData->email); }); diff --git a/tests/admin/Unit/Models/StaffTest.php b/tests/admin/Unit/Models/StaffTest.php new file mode 100644 index 0000000000..bdaad06067 --- /dev/null +++ b/tests/admin/Unit/Models/StaffTest.php @@ -0,0 +1,72 @@ +group('lunar.admin.models'); + +test('can get full name', function () { + $staff = \Lunar\Admin\Models\Staff::factory()->create([ + 'first_name' => 'Joe', + 'last_name' => 'Bloggs', + ]); + + expect($staff->full_name)->toBe('Joe Bloggs'); +}); + +test('can search staff by name', function () { + \Lunar\Admin\Models\Staff::factory()->create([ + 'first_name' => 'Joe', + 'last_name' => 'Bloggs', + ]); + + \Lunar\Admin\Models\Staff::factory()->create([ + 'first_name' => 'Tim', + 'last_name' => 'Bloggs', + ]); + + \Lunar\Admin\Models\Staff::factory()->create([ + 'first_name' => 'Bill', + 'last_name' => 'Chance', + ]); + + expect(\Lunar\Admin\Models\Staff::search('Bloggs')->get())->toHaveCount(2) + ->and(\Lunar\Admin\Models\Staff::search('Bill')->get())->toHaveCount(1) + ->and(\Lunar\Admin\Models\Staff::search('Joe Bloggs')->get())->toHaveCount(1); +}); + +test('can get first name by old key without underscore', function () { + $staff = \Lunar\Admin\Models\Staff::factory()->create([ + 'first_name' => 'Joe', + ]); + + expect($staff->firstname)->toBe('Joe'); +}); + +test('can get last name by old key without underscore', function () { + $staff = \Lunar\Admin\Models\Staff::factory()->create([ + 'last_name' => 'Bloggs', + ]); + + expect($staff->lastname)->toBe('Bloggs'); +}); + +test('can set first name by old key without underscore', function () { + $staff = \Lunar\Admin\Models\Staff::factory()->create([ + 'first_name' => 'Joe', + ]); + + $staff->firstname = 'Tim'; + + expect($staff->firstname)->toBe('Tim'); + expect($staff->first_name)->toBe('Tim'); +}); + +test('can set last name by old key without underscore', function () { + $staff = \Lunar\Admin\Models\Staff::factory()->create([ + 'last_name' => 'Bloggs', + ]); + + $staff->lastname = 'Chance'; + + expect($staff->lastname)->toBe('Chance'); + expect($staff->last_name)->toBe('Chance'); +}); diff --git a/tests/admin/Unit/Models/TestCase.php b/tests/admin/Unit/Models/TestCase.php new file mode 100644 index 0000000000..f765d78668 --- /dev/null +++ b/tests/admin/Unit/Models/TestCase.php @@ -0,0 +1,13 @@ +