refactor(user): menambahkan 1 method gradies di enum status

-merubah cara menampilkan data dari menggunakan tabel menjadi foreach card
-menghapus dispatch datatable
-membuat referral code factory
-menyesuaikan test
This commit is contained in:
Yoga Pangestu 2025-10-15 20:35:30 +07:00
parent 5a49bc8ba4
commit bfe5207d7f
10 changed files with 457 additions and 253 deletions

View File

@ -30,4 +30,13 @@ public function color()
self::SUSPENDED => 'red',
};
}
public function gradient(): string
{
return match ($this) {
self::ACTIVE => 'bg-gradient-to-b from-emerald-800 to-emerald-400',
self::INACTIVE => 'bg-gradient-to-b from-yellow-800 to-yellow-400',
self::SUSPENDED => 'bg-gradient-to-b from-red-800 to-red-400',
};
}
}

View File

@ -1,192 +0,0 @@
<?php
namespace App\Livewire\Datatable\Studio\Master;
use App\Enums\UserStatus;
use App\Models\Employee;
use App\Traits\Datatable\WithAppendColumn;
use App\Traits\Datatable\WithConfiguration;
use App\Traits\Datatable\WithPrependColumn;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Blade;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Columns\ArrayColumn;
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter;
class UsersTable extends DataTableComponent
{
use WithAppendColumn, WithConfiguration, WithPrependColumn;
protected $model = Employee::class;
public function columns(): array
{
return [
Column::make('Nama Lengkap')
->label(
fn ($row) => <<<HTML
<div>
<div>{$row->full_name}</div>
<span class="text-xs text-gray-400">{$row->code}</span>
</div>
HTML
)
->searchable(
fn ($query, $searchTerm) => $query->where('full_name', 'like', "%{$searchTerm}%")
->orWhere('code', 'like', "%{$searchTerm}%")
)
->html(),
Column::make('Kredensial')
->label(
fn ($row) => <<<HTML
<div>
<div>{$row?->user?->email}</div>
<span class="text-xs text-gray-400">{$row?->user?->username}</span>
</div>
HTML
)
->searchable(
fn ($query, $searchTerm) => $query->whereHas(
'user',
fn ($q) => $q->where('email', 'like', "%{$searchTerm}%")
->orWhere('username', 'like', "%{$searchTerm}%")
)
)
->html(),
Column::make('Nomor Telepon', 'phone_number')->searchable(),
Column::make('Jenis Kelamin', 'gender')
->format(fn ($value) => Blade::render(
'<flux:badge color="'.$value->color().'">'
.$value->label()
.'</flux:badge>'
))
->html(),
Column::make('Kode Referral', 'user.referralCode.code')
->format(
fn ($value) => $value
? Blade::render('<flux:badge color="zinc">'.$value.'</flux:badge>')
: ''
)
->html(),
Column::make('Gaji Pokok', 'base_salary')
->searchable()
->sortable()
->format(fn ($value) => currency($value, 'Rp')),
Column::make('Alamat', 'address')->searchable(),
ArrayColumn::make('Outlet')
->data(fn ($value, $row) => $row->user->outlets->pluck('name')->toArray())
->outputFormat(fn ($index, $value) => Blade::render('<span class="text-xs text-gray-400 border border-gray-400 rounded px-1">'.$value.'</span>'))
->flexRow(['class' => 'gap-2 flex-wrap']),
Column::make('Tanggal')
->label(function ($row) {
$birthdate = formatDate($row->birthdate);
$birthAgo = getAge($row->birthdate);
$hireDate = formatDate($row?->user?->hire_date);
$openedAgo = timeAgo($row?->user?->hire_date);
$resigndate = formatDate($row?->user?->resign_date);
$resignAgo = timeAgo($row?->user?->resign_date);
return <<<HTML
<div class="flex flex-col text-xs text-gray-700 dark:text-gray-300 gap-0.5">
<div>
<span class="font-medium text-gray-900 dark:text-white">Tgl Lahir:</span>
<span>{$birthdate}</span>
<span class="text-gray-500">({$birthAgo})</span>
</div>
<div>
<span class="font-medium text-gray-900 dark:text-white">Tgl Bergabung:</span>
<span>{$hireDate}</span>
<span class="text-gray-500">({$openedAgo})</span>
</div>
<div>
<span class="font-medium text-gray-900 dark:text-white">Tgl Resign:</span>
<span>{$resigndate}</span>
<span class="text-gray-500">({$resignAgo})</span>
</div>
</div>
HTML;
})
->html(),
Column::make('Status', 'user.status')
->format(
fn ($value) => Blade::render('<flux:badge color="'.UserStatus::tryFrom($value)->color().'">'.UserStatus::tryFrom($value)->label().'</flux:badge>')
)
->html(),
Column::make('Aksi')
->label(function ($row) {
$actions = '';
if (auth()->id() !== $row?->user?->id) {
if (auth()->user()->can('update user')) {
$actions .= view('components.datatables.edit', [
'id' => $row->hash,
'editRoute' => route('studio.master.user.edit', $row->hash),
])->render();
}
if (auth()->user()->can('delete user')) {
$actions .= view('components.datatables.delete', [
'id' => $row->hash,
'deleteRoute' => route('studio.master.user.delete', $row->hash),
])->render();
}
}
return $actions;
})
->html(),
];
}
public function builder(): Builder
{
return Employee::query()
->select(
'employees.id',
'employees.user_id',
'employees.code',
'employees.full_name',
'employees.phone_number',
'employees.gender',
'employees.birthdate',
'employees.base_salary',
'employees.address'
)
->with([
'user',
'user.referralCode',
'user.outlets',
]);
}
public function filters(): array
{
return [
MultiSelectFilter::make('Status')
->options(
collect(UserStatus::cases())
->mapWithKeys(fn ($case) => [$case->value => $case->label()])
->toArray()
)
->filter(function (Builder $builder, array $values) {
$builder->whereHas(
'user',
fn ($q) => $q->whereIn('status', $values)
);
}),
];
}
}

View File

@ -31,8 +31,6 @@ public function save()
$this->form->store();
$this->dispatch('refreshDatatable');
$this->toast('Pegawai berhasil ditambahkan.');
$this->redirectRoute('studio.master.user.index', navigate: true);

View File

@ -33,8 +33,6 @@ public function save()
$this->form->update();
$this->dispatch('refreshDatatable');
$this->toast('Pegawai berhasil diperbarui.');
$this->redirectRoute('studio.master.user.index', navigate: true);

View File

@ -2,6 +2,8 @@
namespace App\Livewire\Studio\Master\User;
use App\Enums\UserStatus;
use App\Models\Employee;
use App\Models\User;
use App\Traits\WithConfirmation;
use App\Traits\WithToast;
@ -14,12 +16,69 @@ class Index extends Component
{
use WithConfirmation, WithToast;
public array $employees = [];
public array $status = [];
public function mount()
{
$this->loadEmployees();
$this->status = UserStatus::cases();
}
protected function loadEmployees()
{
$this->employees = Employee::with(['user', 'user.referralCode', 'user.outlets'])
->when(! empty($this->status), fn ($query) => $query->whereHas('user', fn ($q) => $q->whereIn('status', $this->status)))
->latest()
->get()
->map(fn ($employee) => [
'full_name' => $employee->full_name,
'code' => $employee->code,
'phone_number' => $employee->phone_number,
'address' => $employee->address,
'base_salary' => currency($employee->base_salary, 'Rp'),
'gender' => [
'label' => $employee->gender->label(),
'color' => $employee->gender->color(),
],
'birthdate' => formatDate($employee->birthdate),
'birth_age' => getAge($employee->birthdate),
'user' => [
'id' => $employee->user?->id,
'hash' => $employee->user?->hash,
'email' => $employee->user?->email,
'username' => $employee->user?->username,
'status' => [
'gradient' => $employee->user?->status->gradient(),
],
'hire_date' => formatDate($employee->user?->hire_date),
'hire_ago' => timeAgo($employee->user?->hire_date),
'resign_date' => formatDate($employee->user?->resign_date),
'resign_ago' => timeAgo($employee->user?->resign_date),
],
'referral_code' => $employee->user?->referralCode?->code,
'outlets' => $employee->user?->outlets?->pluck('name')->toArray() ?? [],
])
->toArray();
}
public function updatedStatus()
{
if (empty($this->status)) {
$this->employees = [];
return;
}
$this->loadEmployees();
}
public function delete(User $user)
{
$user->delete();
$this->dispatch('refreshDatatable');
$this->toast('Pegawai berhasil dihapus.');
Flux::modals()->close();

View File

@ -0,0 +1,18 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\ReferralCode>
*/
class ReferralCodeFactory extends Factory
{
public function definition(): array
{
return [
'code' => $this->faker->unique()->randomNumber(6),
];
}
}

View File

@ -3,18 +3,185 @@
<div>
<flux:heading size="xl">{{ $pageTitle }}</flux:heading>
</div>
@if (auth()->user()->can('create user'))
@can('create user')
<div>
<flux:button href="{{ route('studio.master.user.create') }}" variant="primary" wire:navigate.hover
class="text-sm">
Tambah
</flux:button>
</div>
@endif
@endcan
</div>
<div class="mt-6">
<livewire:datatable.studio.master.users-table />
<div class="mb-6 grid grid-cols-1 lg:grid-cols-2 gap-4">
<flux:card class="flex flex-col justify-center">
<div class="flex items-center gap-4 flex-wrap">
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">Status:</span>
@foreach (\App\Enums\UserStatus::cases() as $status)
<div class="flex items-center gap-2">
<flux:badge color="{{ $status->color() }}" size="sm">
{{ $status->label() }}
</flux:badge>
</div>
@endforeach
</div>
</flux:card>
<flux:card>
<flux:checkbox.group wire:model.live="status" variant="buttons">
@foreach (\App\Enums\UserStatus::cases() as $status)
<flux:checkbox value="{{ $status->value }}" label="{{ $status->label() }}" />
@endforeach
</flux:checkbox.group>
</flux:card>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
@foreach ($employees as $employee)
<flux:card
class="relative space-y-4 transition-transform duration-300 ease-out hover:-translate-y-1 hover:shadow-lg">
<div
class="flex flex-col items-center text-center mb-4 p-4 rounded-t-lg {{ $employee['user']['status']['gradient'] }}">
<flux:avatar circle size="xl" initials="{{ substr($employee['full_name'], 0, 2) }}"
class="mb-3" />
<flux:heading size="lg" class="mb-1 text-white">{{ $employee['full_name'] }}
</flux:heading>
<div class="text-sm text-white/80 mb-2">{{ $employee['code'] }}</div>
</div>
<flux:separator></flux:separator>
<div class="space-y-3">
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Kredensial
</flux:heading>
<div class="flex items-start gap-2 text-sm">
<flux:icon.envelope
class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
<div class="text-gray-700 dark:text-gray-300">
<flux:text>{{ $employee['user']['email'] }}</flux:text>
<flux:text class="text-xs">{{ $employee['user']['username'] }}</flux:text>
</div>
</div>
</div>
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Telepon
</flux:heading>
<div class="flex items-center gap-2 text-sm">
<flux:icon.phone class="w-4 h-4 text-gray-500 dark:text-white" />
<flux:text>{{ $employee['phone_number'] }}</flux:text>
</div>
</div>
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Alamat
</flux:heading>
<div class="flex items-start gap-2 text-sm">
<flux:icon.map-pin class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
<flux:text>{{ $employee['address'] }}</flux:text>
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Jenis
Kelamin</flux:heading>
<flux:badge color="{{ $employee['gender']['color'] }}" size="sm">
{{ $employee['gender']['label'] }}
</flux:badge>
</div>
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Gaji
</flux:heading>
<flux:text>{{ $employee['base_salary'] }}</flux:text>
</div>
</div>
@if ($employee['referral_code'])
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Kode
Referral</flux:heading>
<flux:badge color="zinc" size="sm">{{ $employee['referral_code'] }}</flux:badge>
</div>
@endif
@if (count($employee['outlets']) > 0)
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Outlet
</flux:heading>
<div class="flex flex-wrap gap-2">
@foreach ($employee['outlets'] as $outlet)
<span class="text-xs text-gray-400 border border-gray-400 rounded px-2 py-1">
{{ $outlet }}
</span>
@endforeach
</div>
</div>
@endif
<div>
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">
Informasi
Tanggal</flux:heading>
<div class="bg-gray-50 dark:bg-gray-800 rounded-lg p-3">
<div class="flex flex-col gap-2 text-xs">
<div>
<span class="font-medium text-gray-900 dark:text-white">Tgl Lahir:</span>
<span
class="text-gray-700 dark:text-gray-300">{{ $employee['birthdate'] }}</span>
<span class="text-gray-500">({{ $employee['birth_age'] }})</span>
</div>
<div>
<span class="font-medium text-gray-900 dark:text-white">Tgl
Bergabung:</span>
<span
class="text-gray-700 dark:text-gray-300">{{ $employee['user']['hire_date'] }}</span>
<span class="text-gray-500">({{ $employee['user']['hire_ago'] }})</span>
</div>
@if ($employee['user']['resign_date'])
<div>
<span class="font-medium text-gray-900 dark:text-white">Tgl
Resign:</span>
<span
class="text-gray-700 dark:text-gray-300">{{ $employee['user']['resign_date'] }}</span>
<span class="text-gray-500">({{ $employee['user']['resign_ago'] }})</span>
</div>
@endif
</div>
</div>
</div>
</div>
@canany(['update user', 'delete user'])
@if (auth()->id() !== $employee['user']['id'])
<flux:separator></flux:separator>
<div class="flex gap-2 pt-2">
@can('update user')
<flux:tooltip content="Ubah">
<flux:button href="{{ route('studio.master.user.edit', $employee['user']['hash']) }}"
wire:navigate.hover variant="primary" color="yellow" icon="pencil-square"
size="sm"></flux:button>
</flux:tooltip>
@endcan
@can('delete user')
<flux:modal.trigger name="delete">
<flux:tooltip content="Hapus">
<flux:button variant="danger" icon="trash" size="sm"
wire:click="$dispatch('fn:confirmDelete', {id: '{{ $employee['user']['hash'] }}'})">
</flux:button>
</flux:tooltip>
</flux:modal.trigger>
@endcan
</div>
@endif
@endcanany
</flux:card>
@endforeach
</div>
</div>
@include('components.confirmation.delete')

View File

@ -1,28 +1,74 @@
<?php
use App\Enums\UserStatus;
use App\Livewire\Studio\Master\User\Create;
use App\Livewire\Studio\Master\User\Index;
use App\Models\Employee;
use App\Models\Outlet;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Gate;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
uses(RefreshDatabase::class);
it('renders successfully', function () {
Livewire::test(Create::class)
beforeEach(function () {
$this->user = User::factory()->create();
});
it('renders create user page', function () {
Livewire::actingAs($this->user)
->test(Create::class)
->assertViewIs('livewire.studio.master.user.form')
->assertViewHas('pageTitle', 'Tambah Pegawai');
});
it('can create an user', function () {
$user = User::factory()->raw();
it('mounts outlets correctly', function () {
$outlets = Outlet::factory()->count(3)->create();
$employee = Employee::factory()->raw();
$component = Livewire::actingAs($this->user)
->test(Create::class);
$data = array_merge($user, $employee);
expect($component->outlets)->toHaveCount(3);
foreach ($outlets as $outlet) {
expect($component->outlets)->toHaveKey($outlet->id);
expect($component->outlets[$outlet->id])->toBe($outlet->name);
}
});
Livewire::test(Create::class)
it('prevents creation when unauthorized', function () {
Gate::define('create user', fn () => false);
Livewire::actingAs($this->user)
->test(Create::class)
->call('save')
->assertForbidden();
});
it('saves outlet successfully when authorized', function () {
$permission = Permission::create(['name' => 'create user']);
$this->user->givePermissionTo($permission);
$outlets = Outlet::factory()->count(2)->create();
$userRaw = User::factory()->make()->toArray();
$employeeRaw = Employee::factory()->make()->toArray();
$data = array_merge($userRaw, [
'full_name' => $employeeRaw['full_name'],
'phone_number' => $employeeRaw['phone_number'],
'base_salary' => $employeeRaw['base_salary'],
'birthdate' => $employeeRaw['birthdate'],
'hire_date' => $employeeRaw['hire_date'],
'address' => $employeeRaw['address'],
'gender' => $employeeRaw['gender'],
'status' => UserStatus::ACTIVE->value,
'outlet_ids' => $outlets->pluck('id')->toArray(),
]);
Livewire::actingAs($this->user)
->test(Create::class)
->set('form.full_name', $data['full_name'])
->set('form.username', $data['username'])
->set('form.email', $data['email'])
@ -31,15 +77,26 @@
->set('form.birthdate', $data['birthdate'])
->set('form.hire_date', $data['hire_date'])
->set('form.address', $data['address'])
->set('form.gender', $data['gender']->value)
->set('form.status', $data['status']->value)
->set('form.gender', $data['gender'])
->set('form.status', $data['status'])
->set('form.outlet_ids', $data['outlet_ids'])
->call('save')
->assertHasNoErrors()
->assertDispatched('refreshDatatable')
->assertRedirect(Index::class);
$user = User::where('email', $data['email'])->first();
$this->assertDatabaseHas('users', [
'email' => $data['email'],
'id' => $user->id,
'username' => $data['username'],
'email' => $data['email'],
]);
$this->assertDatabaseHas('employees', [
'user_id' => $user->id,
'full_name' => $data['full_name'],
'phone_number' => $data['phone_number'],
]);
expect($user->outlets->pluck('id')->toArray())->toMatchArray($data['outlet_ids']);
});

View File

@ -1,53 +1,114 @@
<?php
use App\Enums\Gender;
use App\Enums\UserStatus;
use App\Livewire\Studio\Master\User\Edit;
use App\Livewire\Studio\Master\User\Index;
use App\Models\Employee;
use App\Models\Outlet;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Gate;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
uses(RefreshDatabase::class);
it('renders successfully', function () {
$user = User::factory()
->has(Employee::factory())
->create();
beforeEach(function () {
$this->admin = User::factory()->create();
});
Livewire::test(Edit::class, ['user' => $user])
function mountEditUser(User $admin, User $user)
{
return Livewire::actingAs($admin)->test(Edit::class, ['user' => $user]);
}
it('renders page successfully', function () {
$userToEdit = User::factory()->has(Employee::factory())->create();
mountEditUser($this->admin, $userToEdit)
->assertViewIs('livewire.studio.master.user.form')
->assertViewHas('pageTitle', 'Ubah Pegawai');
});
it('can update an user', function () {
$existingUser = User::factory()
->has(Employee::factory())
->create();
it('mounts form with existing user data', function () {
$userToEdit = User::factory()->has(Employee::factory())->create();
$user = User::factory()->raw();
$employee = Employee::factory()->raw();
$component = mountEditUser($this->admin, $userToEdit);
$data = array_merge($user, $employee);
expect($component->form->username)->toBe($userToEdit->username);
expect($component->form->email)->toBe($userToEdit->email);
expect($component->form->full_name)->toBe($userToEdit->employee->full_name);
expect($component->form->phone_number)->toBe($userToEdit->employee->phone_number);
expect($component->form->outlet_ids)->toBe($userToEdit->outlets->pluck('id')->toArray());
});
Livewire::test(Edit::class, ['user' => $existingUser])
->set('form.full_name', $data['full_name'])
it('prevents update when user is unauthorized', function () {
$userToEdit = User::factory()->has(Employee::factory())->create();
Gate::define('update user', fn () => false);
mountEditUser($this->admin, $userToEdit)
->call('save')
->assertForbidden();
});
it('updates user successfully when authorized', function () {
$permission = Permission::create(['name' => 'update user']);
$this->admin->givePermissionTo($permission);
$userToEdit = User::factory()->has(Employee::factory())->create();
$outlets = Outlet::factory()->count(3)->create();
$userRaw = User::factory()->raw();
$employeeRaw = Employee::factory()->raw();
$data = array_merge($userRaw, $employeeRaw, [
'outlet_ids' => $outlets->pluck('id')->toArray(),
'status' => UserStatus::ACTIVE->value,
'gender' => $employeeRaw['gender'] ?? Gender::MALE->value,
]);
$data = array_merge($data, [
'full_name' => $data['full_name'],
'phone_number' => $data['phone_number'],
'outlet_ids' => $outlets->pluck('id')->toArray(),
'status' => UserStatus::ACTIVE->value,
'gender' => Gender::MALE->value,
'birthdate' => $data['birthdate'],
'hire_date' => $data['hire_date'],
'address' => $data['address'],
'base_salary' => $data['base_salary'],
]);
mountEditUser($this->admin, $userToEdit)
->set('form.username', $data['username'])
->set('form.email', $data['email'])
->set('form.full_name', $data['full_name'])
->set('form.phone_number', $data['phone_number'])
->set('form.base_salary', $data['base_salary'])
->set('form.address', $data['address'])
->set('form.birthdate', $data['birthdate'])
->set('form.hire_date', $data['hire_date'])
->set('form.address', $data['address'])
->set('form.gender', $data['gender']->value)
->set('form.status', $data['status']->value)
->set('form.base_salary', $data['base_salary'])
->set('form.gender', $data['gender'])
->set('form.status', $data['status'])
->set('form.outlet_ids', $data['outlet_ids'])
->call('save')
->assertHasNoErrors()
->assertDispatched('refreshDatatable')
->assertRedirect(Index::class);
$userToEdit->refresh();
$this->assertDatabaseHas('users', [
'id' => $existingUser->id,
'email' => $data['email'],
'id' => $userToEdit->id,
'username' => $data['username'],
'email' => $data['email'],
]);
$this->assertDatabaseHas('employees', [
'user_id' => $userToEdit->id,
'full_name' => $data['full_name'],
'phone_number' => $data['phone_number'],
]);
expect($userToEdit->outlets->pluck('id')->toArray())->toBe($data['outlet_ids']);
});

View File

@ -1,39 +1,68 @@
<?php
use App\Enums\UserStatus;
use App\Livewire\Studio\Master\User\Index;
use App\Models\Employee;
use App\Models\ReferralCode;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
uses(RefreshDatabase::class);
it('renders successfully', function () {
Livewire::test(Index::class)
beforeEach(function () {
$this->user = User::factory()->create();
});
it('renders user index page successfully', function () {
Livewire::actingAs($this->user)
->test(Index::class)
->assertViewIs('livewire.studio.master.user.index')
->assertViewHas('pageTitle', 'Pegawai');
});
it('displays all users', function () {
User::factory()
->count(10)
it('mounts employees correctly', function () {
$userWithEmployee = User::factory()
->has(Employee::factory())
->has(ReferralCode::factory())
->create();
$employee = $userWithEmployee->employee;
Livewire::actingAs($this->user)
->test(Index::class)
->assertSee($employee->full_name)
->assertSet('employees.0.full_name', $employee->full_name)
->assertSet('employees.0.user.id', $userWithEmployee->id)
->assertSet('employees.0.referral_code', $userWithEmployee?->referralCode?->code);
});
it('filters employees by status', function () {
$activeUser = User::factory()->create(['status' => UserStatus::ACTIVE->value]);
$inactiveUser = User::factory()->create(['status' => UserStatus::INACTIVE->value]);
$activeUser->employee()->save(Employee::factory()->make());
$inactiveUser->employee()->save(Employee::factory()->make());
$component = Livewire::actingAs($this->user)
->test(Index::class);
$component->set('status', [UserStatus::ACTIVE->value]);
$employees = $component->employees;
expect(count($employees))->toBe(1);
expect($employees[0]['user']['id'])->toBe($activeUser->id);
});
it('deletes a user successfully', function () {
$userToDelete = User::factory()
->has(Employee::factory())
->create();
$user = User::first();
Livewire::actingAs($this->user)
->test(Index::class)
->call('delete', $userToDelete)
->assertHasNoErrors();
Livewire::test(Index::class)->assertSee($user->email);
});
it('can delete an user', function () {
$user = User::factory()
->has(Employee::factory())
->create();
Livewire::test(Index::class)
->call('delete', $user)
->assertHasNoErrors()
->assertDispatched('refreshDatatable');
expect(User::count())->toBe(0);
$this->assertSoftDeleted('users', ['id' => $userToDelete->id]);
});