refactor(user): memisahkan menjadi tangung jawab " kecil
- menghapus map dan toArray() - menyesuaikan view dengan perubahan tersebut - menyesuaikan testing - kasih return type
This commit is contained in:
parent
c41d1b1fb2
commit
a99d7863b9
@ -37,13 +37,20 @@ class UserForm extends Form
|
||||
|
||||
public string $gender = '';
|
||||
|
||||
public string $status = '1';
|
||||
public int $status = UserStatus::ACTIVE->value;
|
||||
|
||||
/** @var array<int> */
|
||||
public array $outlet_ids = [];
|
||||
|
||||
/** @var array<int> */
|
||||
public array $role_ids = [];
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return array_merge($this->getBasicRules(), $this->getRelationshipRules());
|
||||
}
|
||||
|
||||
private function getBasicRules(): array
|
||||
{
|
||||
return [
|
||||
'full_name' => ['required', 'string', 'max:100'],
|
||||
@ -56,6 +63,12 @@ public function rules(): array
|
||||
'address' => ['nullable', 'string'],
|
||||
'gender' => ['required', Rule::in(Gender::cases())],
|
||||
'status' => ['required', Rule::in(UserStatus::cases())],
|
||||
];
|
||||
}
|
||||
|
||||
private function getRelationshipRules(): array
|
||||
{
|
||||
return [
|
||||
'outlet_ids' => ['required', 'array', 'min:1'],
|
||||
'outlet_ids.*' => Rule::exists('outlets', 'id'),
|
||||
'role_ids' => ['required', 'array', 'min:1'],
|
||||
@ -81,11 +94,19 @@ public function validationAttributes(): array
|
||||
];
|
||||
}
|
||||
|
||||
public function setUser(User $user)
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$user->load(['employee', 'outlets']);
|
||||
$user->load(['employee', 'outlets', 'roles']);
|
||||
|
||||
$this->user = $user;
|
||||
|
||||
$this->fillBasicAttributes($user);
|
||||
$this->outlet_ids = $user->outlets->pluck('id')->toArray();
|
||||
$this->role_ids = $user->roles->pluck('id')->toArray();
|
||||
}
|
||||
|
||||
private function fillBasicAttributes(User $user): void
|
||||
{
|
||||
$employee = $user->employee;
|
||||
|
||||
$this->full_name = $employee->full_name;
|
||||
@ -98,88 +119,112 @@ public function setUser(User $user)
|
||||
$this->address = $employee->address;
|
||||
$this->gender = $employee->gender->value;
|
||||
$this->status = $user->status->value;
|
||||
$this->outlet_ids = $user->outlets->pluck('id')->toArray();
|
||||
$this->role_ids = $user->roles->pluck('id')->toArray();
|
||||
}
|
||||
|
||||
public function store()
|
||||
public function store(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$data = $this->all();
|
||||
|
||||
if ($data['status'] != UserStatus::ACTIVE) {
|
||||
$data['resign_date'] = now();
|
||||
} else {
|
||||
$data['resign_date'] = null;
|
||||
}
|
||||
$data = $this->prepareDataForSave();
|
||||
|
||||
DB::transaction(function () use ($data) {
|
||||
$user = User::create([
|
||||
...$data,
|
||||
'password' => Hash::make(config('myconfig.password_default')),
|
||||
'referral_code' => generateReferralCode($data['username'], User::max('id') + 1),
|
||||
'status' => $data['status'],
|
||||
]);
|
||||
|
||||
Employee::create([
|
||||
'user_id' => $user->id,
|
||||
'full_name' => $data['full_name'],
|
||||
'code' => Employee::generateEmployeeCode(),
|
||||
'phone_number' => $data['phone_number'],
|
||||
'base_salary' => replaceCurrency($data['base_salary']),
|
||||
'birthdate' => $data['birthdate'],
|
||||
'hire_date' => $data['hire_date'],
|
||||
'resign_date' => $data['resign_date'],
|
||||
'address' => $data['address'],
|
||||
'gender' => $data['gender'],
|
||||
]);
|
||||
|
||||
ReferralCode::create([
|
||||
'user_id' => $user->id,
|
||||
'code' => generateReferralCode($data['username'], $user->id),
|
||||
]);
|
||||
|
||||
$user->outlets()->attach($this->outlet_ids);
|
||||
|
||||
$user->assignRole(array_map('intval', $this->role_ids));
|
||||
$user = $this->createUser($data);
|
||||
$this->createEmployee($user, $data);
|
||||
$this->createReferralCode($user, $data);
|
||||
$this->assignOutletsAndRoles($user);
|
||||
});
|
||||
}
|
||||
|
||||
public function update()
|
||||
private function prepareDataForSave(): array
|
||||
{
|
||||
$data = $this->all();
|
||||
|
||||
$data['resign_date'] = $data['status'] != UserStatus::ACTIVE->value
|
||||
? now()
|
||||
: null;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function createUser(array $data): User
|
||||
{
|
||||
return User::create([
|
||||
'username' => $data['username'],
|
||||
'email' => $data['email'],
|
||||
'password' => Hash::make(config('myconfig.password_default')),
|
||||
'status' => $data['status'],
|
||||
]);
|
||||
}
|
||||
|
||||
private function createEmployee(User $user, array $data): void
|
||||
{
|
||||
Employee::create([
|
||||
'user_id' => $user->id,
|
||||
'full_name' => $data['full_name'],
|
||||
'code' => Employee::generateEmployeeCode(),
|
||||
'phone_number' => $data['phone_number'],
|
||||
'base_salary' => replaceCurrency($data['base_salary']),
|
||||
'birthdate' => $data['birthdate'],
|
||||
'hire_date' => $data['hire_date'],
|
||||
'resign_date' => $data['resign_date'],
|
||||
'address' => $data['address'],
|
||||
'gender' => $data['gender'],
|
||||
]);
|
||||
}
|
||||
|
||||
private function createReferralCode(User $user, array $data): void
|
||||
{
|
||||
ReferralCode::create([
|
||||
'user_id' => $user->id,
|
||||
'code' => generateReferralCode($data['username'], $user->id),
|
||||
]);
|
||||
}
|
||||
|
||||
private function assignOutletsAndRoles(User $user): void
|
||||
{
|
||||
$user->outlets()->attach($this->outlet_ids);
|
||||
$user->assignRole(array_map('intval', $this->role_ids));
|
||||
}
|
||||
|
||||
public function update(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$data = $this->all();
|
||||
|
||||
if ($data['status'] == UserStatus::INACTIVE->value) {
|
||||
$data['resign_date'] = now();
|
||||
} else {
|
||||
$data['resign_date'] = null;
|
||||
}
|
||||
$data = $this->prepareDataForSave();
|
||||
|
||||
DB::transaction(function () use ($data) {
|
||||
$this->user->update([
|
||||
...$data,
|
||||
'status' => $data['status'],
|
||||
]);
|
||||
|
||||
$this->user->employee->update([
|
||||
'user_id' => $this->user->id,
|
||||
'full_name' => $data['full_name'],
|
||||
'phone_number' => $data['phone_number'],
|
||||
'base_salary' => replaceCurrency($data['base_salary']),
|
||||
'birthdate' => $data['birthdate'],
|
||||
'hire_date' => $data['hire_date'],
|
||||
'resign_date' => $data['resign_date'],
|
||||
'address' => $data['address'],
|
||||
'gender' => $data['gender'],
|
||||
'resign_date' => $data['resign_date'],
|
||||
]);
|
||||
|
||||
$this->user->outlets()->sync($this->outlet_ids);
|
||||
|
||||
$this->user->syncRoles(array_map('intval', $this->role_ids));
|
||||
$this->updateUser($data);
|
||||
$this->updateEmployee($data);
|
||||
$this->syncOutletsAndRoles();
|
||||
});
|
||||
}
|
||||
|
||||
private function updateUser(array $data): void
|
||||
{
|
||||
$this->user->update([
|
||||
'username' => $data['username'],
|
||||
'email' => $data['email'],
|
||||
'status' => $data['status'],
|
||||
]);
|
||||
}
|
||||
|
||||
private function updateEmployee(array $data): void
|
||||
{
|
||||
$this->user->employee->update([
|
||||
'full_name' => $data['full_name'],
|
||||
'phone_number' => $data['phone_number'],
|
||||
'base_salary' => replaceCurrency($data['base_salary']),
|
||||
'birthdate' => $data['birthdate'],
|
||||
'hire_date' => $data['hire_date'],
|
||||
'resign_date' => $data['resign_date'],
|
||||
'address' => $data['address'],
|
||||
'gender' => $data['gender'],
|
||||
]);
|
||||
}
|
||||
|
||||
private function syncOutletsAndRoles(): void
|
||||
{
|
||||
$this->user->outlets()->sync($this->outlet_ids);
|
||||
$this->user->syncRoles(array_map('intval', $this->role_ids));
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
use App\Traits\WithRoleSelector;
|
||||
use App\Traits\WithToast;
|
||||
use App\Traits\WithUpdatedData;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
use Spatie\Permission\Models\Role;
|
||||
@ -24,14 +25,14 @@ class Create extends Component
|
||||
|
||||
public array $roles = [];
|
||||
|
||||
public function mount()
|
||||
public function mount(): void
|
||||
{
|
||||
$this->outlets = Outlet::pluck('name', 'id')->toArray();
|
||||
|
||||
$this->roles = Role::where('name', '!=', 'Developer')->orderBy('id')->pluck('name', 'id')->toArray();
|
||||
}
|
||||
|
||||
public function save()
|
||||
public function save(): void
|
||||
{
|
||||
$this->canOrAbort('create user');
|
||||
|
||||
@ -42,7 +43,7 @@ public function save()
|
||||
$this->redirectRoute('studio.master.user.index');
|
||||
}
|
||||
|
||||
public function render()
|
||||
public function render(): View
|
||||
{
|
||||
return view('livewire.studio.master.user.form', [
|
||||
'pageTitle' => 'Tambah Pegawai',
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
use App\Traits\WithRoleSelector;
|
||||
use App\Traits\WithToast;
|
||||
use App\Traits\WithUpdatedData;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
use Spatie\Permission\Models\Role;
|
||||
@ -17,7 +18,7 @@
|
||||
#[Title('Ubah Pegawai')]
|
||||
class Edit extends Component
|
||||
{
|
||||
use WithAuthorization, WithOutletSelector, WithRoleSelector, WithToast,WithUpdatedData;
|
||||
use WithAuthorization, WithOutletSelector, WithRoleSelector, WithToast, WithUpdatedData;
|
||||
|
||||
public UserForm $form;
|
||||
|
||||
@ -25,7 +26,7 @@ class Edit extends Component
|
||||
|
||||
public array $roles = [];
|
||||
|
||||
public function mount(User $user)
|
||||
public function mount(User $user): void
|
||||
{
|
||||
$this->form->setUser($user);
|
||||
|
||||
@ -34,7 +35,7 @@ public function mount(User $user)
|
||||
$this->roles = Role::where('name', '!=', 'Developer')->orderBy('id')->pluck('name', 'id')->toArray();
|
||||
}
|
||||
|
||||
public function save()
|
||||
public function save(): void
|
||||
{
|
||||
$this->canOrAbort('update user');
|
||||
|
||||
@ -45,7 +46,7 @@ public function save()
|
||||
$this->redirectRoute('studio.master.user.index');
|
||||
}
|
||||
|
||||
public function render()
|
||||
public function render(): View
|
||||
{
|
||||
return view('livewire.studio.master.user.form', [
|
||||
'pageTitle' => 'Ubah Pegawai',
|
||||
|
||||
@ -8,7 +8,9 @@
|
||||
use App\Traits\WithConfirmation;
|
||||
use App\Traits\WithToast;
|
||||
use Flux\Flux;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\View\View;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
|
||||
@ -17,18 +19,19 @@ class Index extends Component
|
||||
{
|
||||
use WithConfirmation, WithSubscribeNotification, WithToast;
|
||||
|
||||
public array $employees = [];
|
||||
/** @var Collection<int, \App\Models\Employee> */
|
||||
public Collection $employees;
|
||||
|
||||
public string $search = '';
|
||||
|
||||
public array $status = [];
|
||||
|
||||
public function mount()
|
||||
public function mount(): void
|
||||
{
|
||||
$this->loadEmployees();
|
||||
}
|
||||
|
||||
protected function loadEmployees()
|
||||
protected function loadEmployees(): void
|
||||
{
|
||||
$this->employees = Employee::with(['user', 'user.referralCode', 'user.outlets'])
|
||||
->when(! empty($this->search), function ($query) {
|
||||
@ -40,52 +43,22 @@ protected function loadEmployees()
|
||||
->when(! empty($this->status), fn ($query) => $query->whereHas('user', fn ($q) => $q->whereIn('status', $this->status)))
|
||||
->withoutDeveloper()
|
||||
->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),
|
||||
'hire_date' => formatDate($employee->hire_date),
|
||||
'hire_ago' => timeAgo($employee->hire_date),
|
||||
'resign_date' => formatDate($employee->resign_date),
|
||||
'resign_ago' => timeAgo($employee->resign_date),
|
||||
'user' => [
|
||||
'id' => $employee->user?->id,
|
||||
'hash' => $employee->user?->hash,
|
||||
'email' => $employee->user?->email,
|
||||
'username' => $employee->user?->username,
|
||||
'status' => [
|
||||
'gradient' => $employee->user?->status->gradient(),
|
||||
],
|
||||
],
|
||||
'referral_code' => $employee->user?->referralCode?->code,
|
||||
'outlets' => $employee->user?->outlets?->pluck('name')->toArray() ?? [],
|
||||
'roles' => $employee->user?->roles?->pluck('name')->toArray() ?? [],
|
||||
])
|
||||
->toArray();
|
||||
->get();
|
||||
}
|
||||
|
||||
public function updatedSearch(string $value)
|
||||
public function updatedSearch(string $value): void
|
||||
{
|
||||
$this->search = $value;
|
||||
|
||||
$this->loadEmployees();
|
||||
}
|
||||
|
||||
public function updatedStatus()
|
||||
public function updatedStatus(): void
|
||||
{
|
||||
$this->loadEmployees();
|
||||
}
|
||||
|
||||
public function delete(User $user)
|
||||
public function delete(User $user): void
|
||||
{
|
||||
$user->delete();
|
||||
|
||||
@ -96,7 +69,7 @@ public function delete(User $user)
|
||||
Flux::modals()->close();
|
||||
}
|
||||
|
||||
public function resetPassword(User $user)
|
||||
public function resetPassword(User $user): void
|
||||
{
|
||||
$user->update(['password' => Hash::make(config('myconfig.password_default'))]);
|
||||
|
||||
@ -105,7 +78,7 @@ public function resetPassword(User $user)
|
||||
Flux::modals()->close();
|
||||
}
|
||||
|
||||
public function render()
|
||||
public function render(): View
|
||||
{
|
||||
return view('livewire.studio.master.user.index', [
|
||||
'pageTitle' => 'Pegawai',
|
||||
|
||||
@ -27,7 +27,7 @@ class="text-sm">
|
||||
|
||||
<flux:separator class="mb-6" />
|
||||
|
||||
@if (!empty($outlets))
|
||||
@if ($outlets->isNotEmpty())
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-start">
|
||||
@foreach ($outlets as $outlet)
|
||||
<flux:card
|
||||
|
||||
@ -35,17 +35,17 @@ class="text-sm">
|
||||
|
||||
<flux:separator class="mb-6" />
|
||||
|
||||
@if (!empty($employees))
|
||||
@if ($employees->isNotEmpty())
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 items-start">
|
||||
@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" name="{{ $employee['full_name'] }}" class="mb-3" />
|
||||
<flux:heading size="lg" class="mb-1 text-white">{{ $employee['full_name'] }}
|
||||
class="flex flex-col items-center text-center mb-4 p-4 rounded-t-lg {{ $employee->user?->status?->gradient() }}">
|
||||
<flux:avatar circle size="xl" name="{{ $employee->full_name }}" 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 class="text-sm text-white/80 mb-2">{{ $employee->code }}</div>
|
||||
</div>
|
||||
|
||||
<flux:separator></flux:separator>
|
||||
@ -59,8 +59,9 @@ class="flex flex-col items-center text-center mb-4 p-4 rounded-t-lg {{ $employee
|
||||
<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>
|
||||
<flux:text>{{ $employee->user?->email }}</flux:text>
|
||||
<flux:text class="text-xs">{{ $employee->user?->username }}
|
||||
</flux:text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -70,7 +71,7 @@ class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
|
||||
</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>
|
||||
<flux:text>{{ $employee->phone_number }}</flux:text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -82,7 +83,7 @@ class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
|
||||
<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>
|
||||
<flux:text>{{ $employee->address }}</flux:text>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@ -92,15 +93,15 @@ class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
|
||||
<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 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>
|
||||
<flux:text>{{ currency($employee->base_salary, 'Rp') }}</flux:text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -108,7 +109,7 @@ class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
|
||||
<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 color="zinc" size="sm">{{ $employee->refferal_code }}
|
||||
</flux:badge>
|
||||
</div>
|
||||
@endif
|
||||
@ -117,9 +118,9 @@ class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
|
||||
<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)
|
||||
@foreach ($employee->user?->outlets as $outlet)
|
||||
<span class="text-xs text-gray-400 border border-gray-400 rounded px-2 py-1">
|
||||
{{ $outlet }}
|
||||
{{ $outlet->name }}
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@ -129,9 +130,9 @@ class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
|
||||
<flux:heading class="uppercase font-semibold text-gray-500 dark:text-gray-400 ">Peran
|
||||
</flux:heading>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@foreach ($employee['roles'] as $role)
|
||||
@foreach ($employee->user?->roles as $role)
|
||||
<span class="text-xs text-gray-400 border border-gray-400 rounded px-2 py-1">
|
||||
{{ $role }}
|
||||
{{ $role->name }}
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@ -146,23 +147,24 @@ class="w-4 h-4 text-gray-500 dark:text-white flex-shrink-0 mt-0.5" />
|
||||
<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>
|
||||
class="text-gray-700 dark:text-gray-300">{{ formatDate($employee->birthdate) }}</span>
|
||||
<span class="text-gray-500">({{ getAge($employee->birthdate) }})</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['hire_date'] }}</span>
|
||||
<span class="text-gray-500">({{ $employee['hire_ago'] }})</span>
|
||||
class="text-gray-700 dark:text-gray-300">{{ formatDate($employee->hire_date) }}</span>
|
||||
<span class="text-gray-500">({{ timeAgo($employee->hire_date) }})</span>
|
||||
</div>
|
||||
@if ($employee['resign_date'])
|
||||
@if ($employee->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['resign_date'] }}</span>
|
||||
<span class="text-gray-500">({{ $employee['resign_ago'] }})</span>
|
||||
class="text-gray-700 dark:text-gray-300">{{ formatDate($employee->resign_date) }}</span>
|
||||
<span
|
||||
class="text-gray-500">({{ timeAgo($employee->resign_date) }})</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@ -170,15 +172,15 @@ class="text-gray-700 dark:text-gray-300">{{ $employee['resign_date'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@canany(['update user', 'delete user'])
|
||||
@if (auth()->id() !== $employee['user']['id'])
|
||||
@canany(['reset password user', 'update user', 'delete user'])
|
||||
@if (auth()->id() !== $employee->user_id)
|
||||
<flux:separator></flux:separator>
|
||||
<div class="flex gap-2 pt-2">
|
||||
@can('reset password user')
|
||||
<flux:modal.trigger name="reset-password">
|
||||
<flux:modal.trigger name="reset-password-confirmation">
|
||||
<flux:tooltip content="Reset Kata Sandi">
|
||||
<flux:button variant="primary" color="blue" icon="lock-open" size="sm"
|
||||
wire:click="$dispatch('fn:confirmAction', { id: '{{ $employee['user']['hash'] }}', title: 'Reset Kata Sandi', message: 'Anda yakin ingin mereset kata sandi pegawai ini menjadi {{ config('myconfig.password_default') }}?' ,confirmButtonText: 'Ya, Reset' })">
|
||||
wire:click="$dispatch('fn:confirmAction', { id: '{{ $employee->user?->hash }}' })">
|
||||
</flux:button>
|
||||
</flux:tooltip>
|
||||
</flux:modal.trigger>
|
||||
@ -186,8 +188,7 @@ class="text-gray-700 dark:text-gray-300">{{ $employee['resign_date'] }}</span>
|
||||
|
||||
@can('update user')
|
||||
<flux:tooltip content="Ubah">
|
||||
<flux:button
|
||||
href="{{ route('studio.master.user.edit', $employee['user']['hash']) }}"
|
||||
<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>
|
||||
@ -197,7 +198,7 @@ class="text-gray-700 dark:text-gray-300">{{ $employee['resign_date'] }}</span>
|
||||
<flux:modal.trigger name="delete-confirmation">
|
||||
<flux:tooltip content="Hapus">
|
||||
<flux:button variant="danger" icon="trash" size="sm"
|
||||
wire:click="$dispatch('fn:confirmAction', {id: '{{ $employee['user']['hash'] }}'})">
|
||||
wire:click="$dispatch('fn:confirmAction', {id: '{{ $employee->user?->hash }}'})">
|
||||
</flux:button>
|
||||
</flux:tooltip>
|
||||
</flux:modal.trigger>
|
||||
@ -210,24 +211,30 @@ class="text-gray-700 dark:text-gray-300">{{ $employee['resign_date'] }}</span>
|
||||
</div>
|
||||
@else
|
||||
@include('components.animations.lottie.not-found')
|
||||
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@include('components.modals.confirmation', [
|
||||
'modalName' => 'confirmation-modal',
|
||||
'modalName' => 'reset-password-confirmation',
|
||||
'modalTitle' => 'Reset Kata Sandi',
|
||||
'modalMessage' =>
|
||||
'Anda yakin ingin mereset kata sandi pegawai ini menjadi ' . config('myconfig.password_default') . '?',
|
||||
'buttonVariant' => 'primary',
|
||||
'buttonColor' => 'reset',
|
||||
'buttonText' => 'Ya, Hapus',
|
||||
'target' => 'resetPassword',
|
||||
])
|
||||
|
||||
@include('components.modals.confirmation', [
|
||||
'modalName' => 'delete-confirmation',
|
||||
'modalTitle' => 'Apakah Anda yakin?',
|
||||
'modalMessage' => 'Data yang berelasi dengan data ini juga akan ikut terhapus.',
|
||||
'buttonVariant' => 'primary',
|
||||
'buttonColor' => 'danger',
|
||||
'buttonText' => 'Ya, Hapus',
|
||||
])
|
||||
@include('components.modals.confirmation', [
|
||||
'modalName' => 'reset-password',
|
||||
'confirmButtonColor' => 'danger',
|
||||
'target' => 'resetPassword',
|
||||
])
|
||||
</flux:main>
|
||||
|
||||
@assets
|
||||
<script src="https://unpkg.com/@lottiefiles/dotlottie-wc@0.8.5/dist/dotlottie-wc.js" type="module"></script>
|
||||
@endassets
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Livewire\Features\SupportTesting\Testable;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
@ -17,18 +18,13 @@
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$roles = collect(['Developer', 'Owner', 'Leader', 'Admin', 'Partner', 'Customer'])
|
||||
->map(fn ($role) => Role::create(['name' => $role]));
|
||||
|
||||
$this->user = User::factory()
|
||||
->active()
|
||||
->has(Employee::factory())
|
||||
->create();
|
||||
|
||||
$this->user->roles()->attach($roles->pluck('id'));
|
||||
});
|
||||
|
||||
function mountCreateComponent(User $user)
|
||||
function mountCreateComponent(User $user): Testable
|
||||
{
|
||||
return Livewire::actingAs($user)->test(Create::class);
|
||||
}
|
||||
@ -39,56 +35,53 @@ function mountCreateComponent(User $user)
|
||||
->assertViewHas('pageTitle', 'Tambah Pegawai');
|
||||
});
|
||||
|
||||
it('mounts outlets and roles correctly', function () {
|
||||
$outlet1 = Outlet::factory()->create(['name' => 'Outlet A']);
|
||||
$outlet2 = Outlet::factory()->create(['name' => 'Outlet B']);
|
||||
it('loads outlets and roles on mount', function () {
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$component = mountCreateComponent($this->user);
|
||||
|
||||
expect($component->outlets)->toBeArray();
|
||||
expect($component->outlets)->toHaveKeys([$outlet1->id, $outlet2->id]);
|
||||
expect($component->outlets[$outlet1->id])->toBe('Outlet A');
|
||||
expect($component->outlets[$outlet2->id])->toBe('Outlet B');
|
||||
|
||||
expect($component->outlets)->toHaveKey($outlet->id);
|
||||
expect($component->roles)->toBeArray();
|
||||
expect($component->roles)->not->toHaveKey(Role::where('name', 'Developer')->first()->id);
|
||||
expect($component->roles)->toHaveKey($role->id);
|
||||
});
|
||||
|
||||
it('excludes developer role from roles list', function () {
|
||||
Role::create(['name' => 'Developer']);
|
||||
$adminRole = Role::create(['name' => 'Admin']);
|
||||
|
||||
$component = mountCreateComponent($this->user);
|
||||
|
||||
$developerRole = Role::where('name', 'Developer')->first();
|
||||
expect($component->roles)->not->toHaveKey($developerRole->id);
|
||||
expect($component->roles)->not->toHaveKey(Role::where('name', 'Developer')->first()->id);
|
||||
expect($component->roles)->toHaveKey($adminRole->id);
|
||||
});
|
||||
|
||||
it('prevents create when user is unauthorized', function () {
|
||||
Gate::define('create user', fn () => false);
|
||||
Gate::define('create user', fn() => false);
|
||||
|
||||
mountCreateComponent($this->user)
|
||||
->call('save')
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
it('saves user successfully when authorized', function () {
|
||||
it('creates user successfully when authorized', function () {
|
||||
$permission = Permission::create(['name' => 'create user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$defaultPassword = config('myconfig.password_default');
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
|
||||
mountCreateComponent($this->user)
|
||||
->set('form.full_name', 'John Doe')
|
||||
->set('form.username', 'johndoe')
|
||||
->set('form.email', 'john@example.com')
|
||||
->set('form.phone_number', '0812 3456 7890')
|
||||
->set('form.base_salary', '5.000.000')
|
||||
->set('form.birthdate', $birthdate)
|
||||
->set('form.hire_date', $hireDate)
|
||||
->set('form.address', 'Jl. Test No. 123')
|
||||
->set('form.base_salary', '5000000')
|
||||
->set('form.birthdate', now()->subYears(25)->format('Y-m-d'))
|
||||
->set('form.hire_date', now()->subMonths(6)->format('Y-m-d'))
|
||||
->set('form.gender', Gender::MALE->value)
|
||||
->set('form.status', UserStatus::ACTIVE->value)
|
||||
->set('form.outlet_ids', [$outlet->id])
|
||||
@ -99,23 +92,20 @@ function mountCreateComponent(User $user)
|
||||
|
||||
$createdUser = User::where('email', 'john@example.com')->first();
|
||||
|
||||
expect($createdUser)->not->toBeNull();
|
||||
expect($createdUser->username)->toBe('johndoe');
|
||||
expect($createdUser->status)->toBe(UserStatus::ACTIVE);
|
||||
expect(Hash::check($defaultPassword, $createdUser->password))->toBeTrue();
|
||||
expect($createdUser)->not->toBeNull()
|
||||
->and($createdUser->username)->toBe('johndoe')
|
||||
->and($createdUser->status)->toBe(UserStatus::ACTIVE)
|
||||
->and(Hash::check($defaultPassword, $createdUser->password))->toBeTrue();
|
||||
|
||||
$this->assertDatabaseHas('employees', [
|
||||
'user_id' => $createdUser->id,
|
||||
'full_name' => 'John Doe',
|
||||
'phone_number' => '0812 3456 7890',
|
||||
'gender' => Gender::MALE,
|
||||
]);
|
||||
|
||||
expect($createdUser->outlets->pluck('id')->toArray())->toContain($outlet->id);
|
||||
expect($createdUser->roles->pluck('id')->toArray())->toContain($role->id);
|
||||
|
||||
expect($createdUser->referralCode)->not->toBeNull();
|
||||
expect($createdUser->referralCode->code)->toBeString();
|
||||
expect($createdUser->outlets)->toHaveCount(1)
|
||||
->and($createdUser->roles)->toHaveCount(1)
|
||||
->and($createdUser->referralCode)->not->toBeNull();
|
||||
});
|
||||
|
||||
it('creates user with inactive status and sets resign date', function () {
|
||||
@ -123,7 +113,7 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -157,7 +147,7 @@ function mountCreateComponent(User $user)
|
||||
$outlet1 = Outlet::factory()->create();
|
||||
$outlet2 = Outlet::factory()->create();
|
||||
$outlet3 = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -188,8 +178,8 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$adminRole = Role::where('name', 'Admin')->first();
|
||||
$leaderRole = Role::where('name', 'Leader')->first();
|
||||
$adminRole = Role::create(['name' => 'Admin']);
|
||||
$leaderRole = Role::create(['name' => 'Leader']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -220,8 +210,7 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$component = mountCreateComponent($this->user);
|
||||
// Clear status to ensure it's validated
|
||||
$component->set('form.status', '');
|
||||
// Don't set any required fields to ensure they're validated
|
||||
$component->call('save')
|
||||
->assertHasErrors([
|
||||
'form.full_name',
|
||||
@ -232,7 +221,6 @@ function mountCreateComponent(User $user)
|
||||
'form.birthdate',
|
||||
'form.hire_date',
|
||||
'form.gender',
|
||||
'form.status',
|
||||
'form.outlet_ids',
|
||||
'form.role_ids',
|
||||
]);
|
||||
@ -326,7 +314,7 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
mountCreateComponent($this->user)
|
||||
->set('form.email', str_repeat('a', 90).'@example.com')
|
||||
->set('form.email', str_repeat('a', 90) . '@example.com')
|
||||
->call('save')
|
||||
->assertHasErrors(['form.email']);
|
||||
});
|
||||
@ -433,7 +421,7 @@ function mountCreateComponent(User $user)
|
||||
->set('form.full_name', 'Test User')
|
||||
->set('form.username', 'testuser')
|
||||
->set('form.email', 'test@example.com')
|
||||
->set('form.status', '')
|
||||
->set('form.status', 99) // Invalid enum value
|
||||
->call('save')
|
||||
->assertHasErrors(['form.status']);
|
||||
});
|
||||
@ -541,7 +529,7 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -573,7 +561,7 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -604,7 +592,7 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -635,7 +623,7 @@ function mountCreateComponent(User $user)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Livewire\Features\SupportTesting\Testable;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
@ -16,44 +17,31 @@
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$roles = collect(['Developer', 'Owner', 'Leader', 'Admin', 'Partner', 'Customer'])
|
||||
->map(fn ($role) => Role::create(['name' => $role]));
|
||||
|
||||
$this->user = User::factory()
|
||||
->active()
|
||||
->has(Employee::factory())
|
||||
->create();
|
||||
|
||||
$this->user->roles()->attach($roles->pluck('id'));
|
||||
});
|
||||
|
||||
function createEditTestUser(array $userAttributes = [], array $employeeAttributes = [])
|
||||
function createEditUser(array $attributes = []): User
|
||||
{
|
||||
$factory = User::factory();
|
||||
|
||||
// Ensure status is set if not provided
|
||||
if (! isset($userAttributes['status'])) {
|
||||
$factory = $factory->active();
|
||||
// Remove status from attributes since we're using active() method
|
||||
unset($userAttributes['status']);
|
||||
}
|
||||
|
||||
if (! empty($userAttributes)) {
|
||||
$factory = $factory->state($userAttributes);
|
||||
}
|
||||
|
||||
return $factory
|
||||
->has(Employee::factory()->state($employeeAttributes))
|
||||
return User::factory()
|
||||
->active()
|
||||
->has(Employee::factory())
|
||||
->state(fn() => array_merge([
|
||||
'status' => fake()->randomElement(UserStatus::cases()),
|
||||
], $attributes))
|
||||
->create();
|
||||
}
|
||||
|
||||
function mountEditComponent(User $user, User $employeeUser)
|
||||
function mountEditComponent(User $user, User $employeeUser): Testable
|
||||
{
|
||||
return Livewire::actingAs($user)->test(Edit::class, ['user' => $employeeUser]);
|
||||
}
|
||||
|
||||
it('renders page successfully', function () {
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser = createEditUser();
|
||||
\Spatie\Permission\Models\Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser->assignRole('Admin');
|
||||
|
||||
mountEditComponent($this->user, $employeeUser)
|
||||
@ -61,55 +49,49 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
->assertViewHas('pageTitle', 'Ubah Pegawai');
|
||||
});
|
||||
|
||||
it('mounts outlets and roles correctly', function () {
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
|
||||
$outlet1 = Outlet::factory()->create(['name' => 'Outlet A']);
|
||||
$outlet2 = Outlet::factory()->create(['name' => 'Outlet B']);
|
||||
it('loads outlets and roles on mount', function () {
|
||||
$employeeUser = createEditUser();
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$component = mountEditComponent($this->user, $employeeUser);
|
||||
|
||||
expect($component->outlets)->toBeArray();
|
||||
expect($component->outlets)->toHaveKeys([$outlet1->id, $outlet2->id]);
|
||||
expect($component->outlets[$outlet1->id])->toBe('Outlet A');
|
||||
expect($component->outlets[$outlet2->id])->toBe('Outlet B');
|
||||
|
||||
expect($component->outlets)->toHaveKey($outlet->id);
|
||||
expect($component->roles)->toBeArray();
|
||||
expect($component->roles)->not->toHaveKey(Role::where('name', 'Developer')->first()->id);
|
||||
expect($component->roles)->toHaveKey($role->id);
|
||||
});
|
||||
|
||||
it('loads existing user data into form', function () {
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::create(['name' => 'Admin']);
|
||||
|
||||
$employeeUser = createEditTestUser(
|
||||
[
|
||||
'username' => 'existinguser',
|
||||
'email' => 'existing@example.com',
|
||||
'status' => UserStatus::ACTIVE,
|
||||
],
|
||||
[
|
||||
'full_name' => 'Existing User',
|
||||
'phone_number' => '0812 3456 7890',
|
||||
'base_salary' => 5000000,
|
||||
'birthdate' => '1995-01-15',
|
||||
'hire_date' => '2020-01-01',
|
||||
'address' => 'Existing Address',
|
||||
'gender' => Gender::MALE,
|
||||
]
|
||||
);
|
||||
$employeeUser = createEditUser([
|
||||
'username' => 'existinguser',
|
||||
'email' => 'existing@example.com',
|
||||
'status' => UserStatus::ACTIVE,
|
||||
]);
|
||||
|
||||
$employeeUser->employee->update([
|
||||
'full_name' => 'Existing User',
|
||||
'phone_number' => '081234567890',
|
||||
'base_salary' => 5000000,
|
||||
'birthdate' => '1995-01-15',
|
||||
'hire_date' => '2020-01-01',
|
||||
'address' => 'Existing Address',
|
||||
'gender' => Gender::MALE,
|
||||
]);
|
||||
|
||||
$employeeUser->assignRole($role->id);
|
||||
$employeeUser->outlets()->attach($outlet->id);
|
||||
|
||||
$component = mountEditComponent($this->user, $employeeUser);
|
||||
|
||||
expect($component->form->full_name)->toBe('Existing User');
|
||||
expect($component->form->username)->toBe('existinguser');
|
||||
expect($component->form->email)->toBe('existing@example.com');
|
||||
expect($component->form->phone_number)->toBe('0812 3456 7890');
|
||||
expect($component->form->base_salary)->toBe('5000000');
|
||||
expect($component->form->full_name)->toBe('Existing User')
|
||||
->and($component->form->username)->toBe('existinguser')
|
||||
->and($component->form->email)->toBe('existing@example.com')
|
||||
->and($component->form->phone_number)->toBe('081234567890')
|
||||
->and($component->form->base_salary)->toBe('5000000');
|
||||
expect($component->form->birthdate)->toBe('1995-01-15');
|
||||
expect($component->form->hire_date)->toBe('2020-01-01');
|
||||
expect($component->form->address)->toBe('Existing Address');
|
||||
@ -120,8 +102,12 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
});
|
||||
|
||||
it('excludes developer role from roles list', function () {
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
Role::firstOrCreate(['name' => 'Admin']);
|
||||
Role::firstOrCreate(['name' => 'Developer']);
|
||||
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$component = mountEditComponent($this->user, $employeeUser);
|
||||
|
||||
@ -130,10 +116,13 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
});
|
||||
|
||||
it('prevents update when user is unauthorized', function () {
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
Gate::define('update user', fn () => false);
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
Gate::define('update user', fn() => false);
|
||||
|
||||
mountEditComponent($this->user, $employeeUser)
|
||||
->call('save')
|
||||
@ -145,9 +134,9 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
$employeeUser->outlets()->attach($outlet->id);
|
||||
|
||||
@ -193,9 +182,9 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$employeeUser = createEditTestUser(['status' => UserStatus::ACTIVE]);
|
||||
$employeeUser = createEditUser(['status' => UserStatus::ACTIVE]);
|
||||
$employeeUser->assignRole($role->id);
|
||||
$employeeUser->outlets()->attach($outlet->id);
|
||||
|
||||
@ -229,9 +218,9 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$employeeUser = createEditTestUser([
|
||||
$employeeUser = createEditUser([
|
||||
'status' => UserStatus::INACTIVE,
|
||||
]);
|
||||
|
||||
@ -274,9 +263,9 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$outlet1 = Outlet::factory()->create();
|
||||
$outlet2 = Outlet::factory()->create();
|
||||
$outlet3 = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
$employeeUser->outlets()->attach($outlet1->id);
|
||||
|
||||
@ -310,10 +299,10 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$adminRole = Role::where('name', 'Admin')->first();
|
||||
$leaderRole = Role::where('name', 'Leader')->first();
|
||||
$adminRole = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$leaderRole = Role::firstOrCreate(['name' => 'Leader']);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($adminRole->id);
|
||||
$employeeUser->outlets()->attach($outlet->id);
|
||||
|
||||
@ -349,9 +338,9 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$outlet1 = Outlet::factory()->create();
|
||||
$outlet2 = Outlet::factory()->create();
|
||||
$outlet3 = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
$employeeUser->outlets()->attach([$outlet1->id, $outlet2->id]);
|
||||
|
||||
@ -388,11 +377,11 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$adminRole = Role::where('name', 'Admin')->first();
|
||||
$leaderRole = Role::where('name', 'Leader')->first();
|
||||
$ownerRole = Role::where('name', 'Owner')->first();
|
||||
$adminRole = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$leaderRole = Role::firstOrCreate(['name' => 'Leader']);
|
||||
$ownerRole = Role::firstOrCreate(['name' => 'Owner']);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole([$adminRole->id, $leaderRole->id]);
|
||||
$employeeUser->outlets()->attach($outlet->id);
|
||||
|
||||
@ -428,8 +417,9 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$component = mountEditComponent($this->user, $employeeUser);
|
||||
|
||||
@ -442,7 +432,6 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
->set('form.birthdate', '')
|
||||
->set('form.hire_date', '')
|
||||
->set('form.gender', '')
|
||||
->set('form.status', '')
|
||||
->set('form.outlet_ids', [])
|
||||
->set('form.role_ids', [])
|
||||
->call('save')
|
||||
@ -455,7 +444,6 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
'form.birthdate',
|
||||
'form.hire_date',
|
||||
'form.gender',
|
||||
'form.status',
|
||||
'form.outlet_ids',
|
||||
'form.role_ids',
|
||||
]);
|
||||
@ -465,11 +453,11 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$employeeUser = createEditTestUser(['username' => 'existinguser']);
|
||||
$employeeUser->assignRole('Admin');
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser(['username' => 'existinguser']);
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -495,14 +483,15 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$existingUser = createEditTestUser(['username' => 'existinguser']);
|
||||
$existingUser->assignRole('Admin');
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$existingUser = createEditUser(['username' => 'existinguser']);
|
||||
$existingUser->assignRole($role->id);
|
||||
|
||||
$employeeUser = createEditTestUser(['username' => 'otheruser']);
|
||||
$employeeUser->assignRole('Admin');
|
||||
$employeeUser = createEditUser(['username' => 'otheruser']);
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -527,11 +516,11 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$employeeUser = createEditTestUser(['email' => 'existing@example.com']);
|
||||
$employeeUser->assignRole('Admin');
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser(['email' => 'existing@example.com']);
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -557,14 +546,15 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$existingUser = createEditTestUser(['email' => 'existing@example.com']);
|
||||
$existingUser->assignRole('Admin');
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$existingUser = createEditUser(['email' => 'existing@example.com']);
|
||||
$existingUser->assignRole($role->id);
|
||||
|
||||
$employeeUser = createEditTestUser(['email' => 'other@example.com']);
|
||||
$employeeUser->assignRole('Admin');
|
||||
$employeeUser = createEditUser(['email' => 'other@example.com']);
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -589,11 +579,12 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(17)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -618,11 +609,12 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
@ -652,12 +644,12 @@ function mountEditComponent(User $user, User $employeeUser)
|
||||
$permission = Permission::create(['name' => 'update user']);
|
||||
$this->user->givePermissionTo($permission);
|
||||
|
||||
$employeeUser = createEditTestUser();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
$employeeUser = createEditUser();
|
||||
$employeeUser->employee->update(['address' => 'Old Address']);
|
||||
$employeeUser->assignRole('Admin');
|
||||
$employeeUser->assignRole($role->id);
|
||||
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::where('name', 'Admin')->first();
|
||||
|
||||
$birthdate = now()->subYears(25)->format('Y-m-d');
|
||||
$hireDate = now()->subMonths(6)->format('Y-m-d');
|
||||
|
||||
@ -5,44 +5,38 @@
|
||||
use App\Models\Employee;
|
||||
use App\Models\Outlet;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Livewire\Features\SupportTesting\Testable;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$roles = collect(['Developer', 'Owner', 'Leader', 'Admin', 'Partner', 'Customer'])
|
||||
->map(fn ($role) => Role::create(['name' => $role]));
|
||||
// Create roles for testing
|
||||
collect(['Developer', 'Owner', 'Leader', 'Admin', 'Partner', 'Customer'])
|
||||
->each(fn($role) => \Spatie\Permission\Models\Role::create(['name' => $role]));
|
||||
|
||||
$this->user = User::factory()
|
||||
->active()
|
||||
->has(Employee::factory())
|
||||
->create();
|
||||
|
||||
$this->user->roles()->attach($roles->pluck('id'));
|
||||
$this->user->assignRole('Admin'); // Give admin role to test user
|
||||
});
|
||||
|
||||
function createIndexTestUser(array $userAttributes = [], array $employeeAttributes = [])
|
||||
function createUser(array $attributes = []): User
|
||||
{
|
||||
$factory = User::factory();
|
||||
|
||||
if (! isset($userAttributes['status'])) {
|
||||
$factory = $factory->active();
|
||||
unset($userAttributes['status']);
|
||||
}
|
||||
|
||||
if (! empty($userAttributes)) {
|
||||
$factory = $factory->state($userAttributes);
|
||||
}
|
||||
|
||||
return $factory
|
||||
->has(Employee::factory()->state($employeeAttributes))
|
||||
return User::factory()
|
||||
->active()
|
||||
->has(Employee::factory())
|
||||
->state(fn() => array_merge([
|
||||
'status' => fake()->randomElement(UserStatus::cases()),
|
||||
], $attributes))
|
||||
->create();
|
||||
}
|
||||
|
||||
function mountIndexComponent(User $user)
|
||||
function mountIndexComponent(User $user): Testable
|
||||
{
|
||||
return Livewire::actingAs($user)->test(Index::class);
|
||||
}
|
||||
@ -53,353 +47,179 @@ function mountIndexComponent(User $user)
|
||||
->assertViewHas('pageTitle', 'Pegawai');
|
||||
});
|
||||
|
||||
it('mounts employees correctly', function () {
|
||||
$employee = createIndexTestUser();
|
||||
$employee->assignRole('Admin');
|
||||
|
||||
mountIndexComponent($this->user)
|
||||
->assertViewHas('employees', function ($employees) use ($employee) {
|
||||
return collect($employees)->contains(
|
||||
fn ($e) => $e['full_name'] === $employee->employee->full_name &&
|
||||
$e['code'] === $employee->employee->code
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('loads employee data with all required fields', function () {
|
||||
$outlet = Outlet::factory()->create();
|
||||
$user = createIndexTestUser();
|
||||
$user->assignRole('Admin');
|
||||
$user->outlets()->attach($outlet->id);
|
||||
$user->referralCode()->create(['code' => 'REF123']);
|
||||
it('loads employees as Eloquent collection', function () {
|
||||
$user = createUser();
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
$employeeData = collect($component->get('employees'))->first(
|
||||
fn ($e) => $e['full_name'] === $user->employee->full_name
|
||||
);
|
||||
|
||||
expect($employeeData)->toHaveKeys([
|
||||
'full_name',
|
||||
'code',
|
||||
'phone_number',
|
||||
'address',
|
||||
'base_salary',
|
||||
'gender',
|
||||
'birthdate',
|
||||
'birth_age',
|
||||
'hire_date',
|
||||
'hire_ago',
|
||||
'resign_date',
|
||||
'resign_ago',
|
||||
'user',
|
||||
'referral_code',
|
||||
'outlets',
|
||||
'roles',
|
||||
]);
|
||||
expect(
|
||||
$component->get('employees')->pluck('id')
|
||||
)->toContain($user->id);
|
||||
});
|
||||
|
||||
expect($employeeData['user'])->toHaveKeys(['id', 'hash', 'email', 'username', 'status']);
|
||||
expect($employeeData['gender'])->toHaveKeys(['label', 'color']);
|
||||
expect($employeeData['user']['status'])->toHaveKeys(['gradient']);
|
||||
it('loads employees with relationships', function () {
|
||||
$user = createUser();
|
||||
$user->assignRole('Admin'); // Assign role so user appears in list
|
||||
$outlet = Outlet::factory()->create();
|
||||
$user->outlets()->attach($outlet->id);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
$loadedEmployee = $component->get('employees')->first(fn($emp) => $emp->user_id === $user->id);
|
||||
|
||||
expect($loadedEmployee)->not->toBeNull()
|
||||
->and($loadedEmployee->relationLoaded('user'))->toBeTrue()
|
||||
->and($loadedEmployee->user->relationLoaded('outlets'))->toBeTrue()
|
||||
->and($loadedEmployee->user->outlets)->toHaveCount(1);
|
||||
});
|
||||
|
||||
it('excludes developer users from listing', function () {
|
||||
$developer = createIndexTestUser();
|
||||
$developer = createUser();
|
||||
$developer->assignRole('Developer');
|
||||
|
||||
$admin = createIndexTestUser();
|
||||
$admin = createUser();
|
||||
$admin->assignRole('Admin');
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$employeeNames = collect($component->get('employees'))->pluck('full_name')->toArray();
|
||||
$employeeNames = $component->get('employees')->pluck('full_name')->toArray();
|
||||
|
||||
expect($employeeNames)->not->toContain($developer->employee->full_name);
|
||||
expect($employeeNames)->toContain($admin->employee->full_name);
|
||||
});
|
||||
|
||||
it('displays all employees', function () {
|
||||
$employees = [];
|
||||
$initialCount = Employee::count();
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$user = createIndexTestUser();
|
||||
$user->assignRole('Admin');
|
||||
$employees[] = $user;
|
||||
createUser();
|
||||
}
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
$employeeCount = count($component->get('employees'));
|
||||
|
||||
expect($employeeCount)->toBeGreaterThanOrEqual(5);
|
||||
expect($component->get('employees'))->toHaveCount($initialCount + 5);
|
||||
expect($component->get('employees')->first())->toBeInstanceOf(Employee::class);
|
||||
});
|
||||
|
||||
it('filters employees by search query - full name', function () {
|
||||
$user1 = createIndexTestUser([], ['full_name' => 'John Doe']);
|
||||
$user1->assignRole('Admin');
|
||||
|
||||
$user2 = createIndexTestUser([], ['full_name' => 'Jane Smith']);
|
||||
$user2->assignRole('Admin');
|
||||
it('filters employees by search query', function () {
|
||||
$user1 = createUser(['username' => 'john_doe']);
|
||||
$user2 = createUser(['username' => 'jane_smith']);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
expect(count($component->get('employees')))->toBeGreaterThanOrEqual(2);
|
||||
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
||||
|
||||
$component->set('search', 'John')
|
||||
->assertSet('search', 'John');
|
||||
// Test filtering by username
|
||||
$filteredComponent = mountIndexComponent($this->user)->set('search', 'john_doe');
|
||||
|
||||
$employees = $component->get('employees');
|
||||
expect(count($employees))->toBeGreaterThanOrEqual(1);
|
||||
expect($employees[0]['full_name'])->toBe('John Doe');
|
||||
expect($filteredComponent->get('employees'))->toHaveCount(1);
|
||||
expect($filteredComponent->get('employees')->first()->user->username)->toBe('john_doe');
|
||||
});
|
||||
|
||||
it('filters employees by search query - employee code', function () {
|
||||
$user1 = createIndexTestUser([], ['code' => 'EMP20240001']);
|
||||
$user1->assignRole('Admin');
|
||||
it('filters employees by status', function () {
|
||||
$activeUser = createUser(['status' => UserStatus::ACTIVE]);
|
||||
$inactiveUser = createUser(['status' => UserStatus::INACTIVE]);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$component->set('search', 'EMP20240001');
|
||||
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
||||
|
||||
$employees = $component->get('employees');
|
||||
expect(collect($employees)->pluck('code'))->toContain('EMP20240001');
|
||||
});
|
||||
$filteredComponent = mountIndexComponent($this->user)->set('status', [UserStatus::ACTIVE->value]);
|
||||
|
||||
it('filters employees by search query - email', function () {
|
||||
$user1 = createIndexTestUser(['email' => 'john@example.com']);
|
||||
$user1->assignRole('Admin');
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$component->set('search', 'john@example.com');
|
||||
|
||||
$employees = $component->get('employees');
|
||||
expect(collect($employees)->pluck('user.email'))->toContain('john@example.com');
|
||||
});
|
||||
|
||||
it('filters employees by search query - username', function () {
|
||||
$user1 = createIndexTestUser(['username' => 'johndoe']);
|
||||
$user1->assignRole('Admin');
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$component->set('search', 'johndoe');
|
||||
|
||||
$employees = $component->get('employees');
|
||||
expect(collect($employees)->pluck('user.username'))->toContain('johndoe');
|
||||
});
|
||||
|
||||
it('filters employees by status - active', function () {
|
||||
$activeUser = createIndexTestUser(['status' => UserStatus::ACTIVE]);
|
||||
$activeUser->assignRole('Admin');
|
||||
|
||||
$inactiveUser = createIndexTestUser(['status' => UserStatus::INACTIVE]);
|
||||
$inactiveUser->assignRole('Admin');
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
expect(count($component->get('employees')))->toBeGreaterThanOrEqual(2);
|
||||
|
||||
$component->set('status', [UserStatus::ACTIVE->value]);
|
||||
|
||||
$employees = $component->get('employees');
|
||||
$activeEmployees = collect($employees)->filter(
|
||||
fn ($e) => $e['user']['status']['gradient'] === (UserStatus::ACTIVE->gradient())
|
||||
);
|
||||
|
||||
expect(count($activeEmployees))->toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('filters employees by status - inactive', function () {
|
||||
$activeUser = createIndexTestUser(['status' => UserStatus::ACTIVE]);
|
||||
$activeUser->assignRole('Admin');
|
||||
|
||||
$inactiveUser = createIndexTestUser(['status' => UserStatus::INACTIVE]);
|
||||
$inactiveUser->assignRole('Admin');
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$component->set('status', [UserStatus::INACTIVE->value]);
|
||||
|
||||
$employees = $component->get('employees');
|
||||
$inactiveEmployees = collect($employees)->filter(
|
||||
fn ($e) => $e['user']['status']['gradient'] === (UserStatus::INACTIVE->gradient())
|
||||
);
|
||||
|
||||
expect(count($inactiveEmployees))->toBeGreaterThanOrEqual(1);
|
||||
expect(count($filteredComponent->get('employees')))->toBeGreaterThanOrEqual(1); // At least the active user
|
||||
expect($filteredComponent->get('employees')->contains(fn($emp) => $emp->user->status->value === UserStatus::ACTIVE->value))->toBeTrue();
|
||||
});
|
||||
|
||||
it('filters employees by multiple statuses', function () {
|
||||
$activeUser = createIndexTestUser(['status' => UserStatus::ACTIVE]);
|
||||
$activeUser->assignRole('Admin');
|
||||
|
||||
$inactiveUser = createIndexTestUser(['status' => UserStatus::INACTIVE]);
|
||||
$inactiveUser->assignRole('Admin');
|
||||
$activeUser = createUser(['status' => UserStatus::ACTIVE]);
|
||||
$inactiveUser = createUser(['status' => UserStatus::INACTIVE]);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$component->set('status', [
|
||||
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
||||
|
||||
$filteredComponent = mountIndexComponent($this->user)->set('status', [
|
||||
UserStatus::ACTIVE->value,
|
||||
UserStatus::INACTIVE->value,
|
||||
]);
|
||||
|
||||
expect(count($component->get('employees')))->toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('filters employees by both search and status', function () {
|
||||
$activeUser = createIndexTestUser(
|
||||
['status' => UserStatus::ACTIVE],
|
||||
['full_name' => 'Active User']
|
||||
);
|
||||
$activeUser->assignRole('Admin');
|
||||
|
||||
$inactiveUser = createIndexTestUser(
|
||||
['status' => UserStatus::INACTIVE],
|
||||
['full_name' => 'Inactive User']
|
||||
);
|
||||
$inactiveUser->assignRole('Admin');
|
||||
|
||||
$component = mountIndexComponent($this->user)
|
||||
->set('search', 'Active')
|
||||
->set('status', [UserStatus::ACTIVE->value]);
|
||||
|
||||
$employees = $component->get('employees');
|
||||
expect(count($employees))->toBeGreaterThanOrEqual(1);
|
||||
expect($employees[0]['full_name'])->toBe('Active User');
|
||||
expect(count($filteredComponent->get('employees')))->toBeGreaterThan(2); // All users with these statuses
|
||||
});
|
||||
|
||||
it('loads employees ordered by latest', function () {
|
||||
$user1 = createIndexTestUser([], ['full_name' => 'First Employee']);
|
||||
$user1->assignRole('Admin');
|
||||
|
||||
$user1 = createUser();
|
||||
sleep(1);
|
||||
|
||||
$user2 = createIndexTestUser([], ['full_name' => 'Second Employee']);
|
||||
$user2->assignRole('Admin');
|
||||
$user2 = createUser();
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$employees = $component->get('employees');
|
||||
$firstEmployee = collect($employees)->first(fn ($e) => $e['full_name'] === 'Second Employee');
|
||||
$secondEmployee = collect($employees)->first(fn ($e) => $e['full_name'] === 'First Employee');
|
||||
|
||||
expect($firstEmployee)->not->toBeNull();
|
||||
expect($secondEmployee)->not->toBeNull();
|
||||
|
||||
// The second employee should appear before the first
|
||||
$firstIndex = array_search('Second Employee', array_column($employees, 'full_name'));
|
||||
$secondIndex = array_search('First Employee', array_column($employees, 'full_name'));
|
||||
|
||||
expect($firstIndex)->toBeLessThan($secondIndex);
|
||||
expect($component->get('employees')->first()->id)->toBe($user2->id);
|
||||
expect($component->get('employees')->last()->id)->toBe($user1->id);
|
||||
});
|
||||
|
||||
it('loads employee with outlets', function () {
|
||||
$outlet1 = Outlet::factory()->create(['name' => 'Outlet A']);
|
||||
$outlet2 = Outlet::factory()->create(['name' => 'Outlet B']);
|
||||
|
||||
$user = createIndexTestUser();
|
||||
$user->assignRole('Admin');
|
||||
$user->outlets()->attach([$outlet1->id, $outlet2->id]);
|
||||
it('loads employees with all required relationships', function () {
|
||||
$user = createUser();
|
||||
$user->assignRole('Admin'); // Ensure user appears in list
|
||||
$outlet = Outlet::factory()->create();
|
||||
$user->outlets()->attach($outlet->id);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
$loadedEmployee = $component->get('employees')->first(fn($emp) => $emp->user_id === $user->id);
|
||||
|
||||
$employeeData = collect($component->get('employees'))->first(
|
||||
fn ($e) => $e['full_name'] === $user->employee->full_name
|
||||
);
|
||||
|
||||
expect($employeeData['outlets'])->toContain('Outlet A', 'Outlet B');
|
||||
});
|
||||
|
||||
it('loads employee with roles', function () {
|
||||
$user = createIndexTestUser();
|
||||
$user->assignRole(['Admin', 'Leader']);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$employeeData = collect($component->get('employees'))->first(
|
||||
fn ($e) => $e['full_name'] === $user->employee->full_name
|
||||
);
|
||||
|
||||
expect($employeeData['roles'])->toContain('Admin', 'Leader');
|
||||
});
|
||||
|
||||
it('loads employee with referral code', function () {
|
||||
$user = createIndexTestUser();
|
||||
$user->assignRole('Admin');
|
||||
$user->referralCode()->create(['code' => 'REF12345']);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$employeeData = collect($component->get('employees'))->first(
|
||||
fn ($e) => $e['full_name'] === $user->employee->full_name
|
||||
);
|
||||
|
||||
expect($employeeData['referral_code'])->toBe('REF12345');
|
||||
expect($loadedEmployee)->not->toBeNull()
|
||||
->and($loadedEmployee->user->outlets)->toHaveCount(1)
|
||||
->and($loadedEmployee->user->roles)->toHaveCount(1) // Admin role assigned
|
||||
->and($loadedEmployee->full_name)->toBe($user->employee->full_name);
|
||||
});
|
||||
|
||||
it('deletes an employee successfully', function () {
|
||||
$employeeUser = createIndexTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
$user = createUser();
|
||||
|
||||
mountIndexComponent($this->user)
|
||||
->call('delete', $employeeUser)
|
||||
->call('delete', $user)
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertSoftDeleted('users', ['id' => $employeeUser->id]);
|
||||
$this->assertSoftDeleted('employees', ['user_id' => $employeeUser->id]);
|
||||
$this->assertSoftDeleted('users', ['id' => $user->id]);
|
||||
$this->assertSoftDeleted('employees', ['user_id' => $user->id]);
|
||||
});
|
||||
|
||||
it('reloads employees after deletion', function () {
|
||||
$employeeUser = createIndexTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
it('handles empty search results gracefully', function () {
|
||||
createUser(['username' => 'existing_user']);
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
$initialCount = count($component->get('employees'));
|
||||
$component = mountIndexComponent($this->user)->set('search', 'NonExistentUser');
|
||||
|
||||
$component->call('delete', $employeeUser);
|
||||
|
||||
expect(count($component->get('employees')))->toBeLessThan($initialCount);
|
||||
expect($component->get('employees'))->toHaveCount(0);
|
||||
});
|
||||
|
||||
it('resets password successfully', function () {
|
||||
$defaultPassword = config('myconfig.password_default');
|
||||
$employeeUser = createIndexTestUser();
|
||||
$employeeUser->assignRole('Admin');
|
||||
$employeeUser->update(['password' => Hash::make('oldpassword')]);
|
||||
it('maintains search state across component lifecycle', function () {
|
||||
$user1 = createUser(['username' => 'test_user']);
|
||||
$user2 = createUser(['username' => 'another_user']);
|
||||
|
||||
$oldPasswordHash = $employeeUser->password;
|
||||
$component = mountIndexComponent($this->user)->set('search', 'test');
|
||||
|
||||
mountIndexComponent($this->user)
|
||||
->call('resetPassword', $employeeUser)
|
||||
->assertHasNoErrors();
|
||||
|
||||
$employeeUser->refresh();
|
||||
|
||||
expect($employeeUser->password)->not->toBe($oldPasswordHash);
|
||||
expect(Hash::check($defaultPassword, $employeeUser->password))->toBeTrue();
|
||||
expect($component->get('employees'))->toHaveCount(1);
|
||||
expect($component->get('search'))->toBe('test');
|
||||
});
|
||||
|
||||
it('does not display delete and edit buttons for current authenticated user', function () {
|
||||
$component = mountIndexComponent($this->user);
|
||||
it('handles status filter with empty array', function () {
|
||||
createUser(['status' => UserStatus::ACTIVE]);
|
||||
createUser(['status' => UserStatus::INACTIVE]);
|
||||
|
||||
$component
|
||||
->assertDontSee('Delete')
|
||||
->assertDontSee('Edit');
|
||||
$component = mountIndexComponent($this->user)->set('status', []);
|
||||
|
||||
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
||||
});
|
||||
|
||||
it('updates search with debounce', function () {
|
||||
$user1 = createIndexTestUser([], ['full_name' => 'John Doe']);
|
||||
$user1->assignRole('Admin');
|
||||
it('loads employees efficiently with eager loading', function () {
|
||||
$users = collect();
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$users->push(createUser());
|
||||
}
|
||||
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$component->set('search', 'John');
|
||||
|
||||
expect($component->get('search'))->toBe('John');
|
||||
});
|
||||
|
||||
it('updates status filter correctly', function () {
|
||||
$component = mountIndexComponent($this->user);
|
||||
|
||||
$component->set('status', ['active']);
|
||||
|
||||
expect($component->get('status'))->toBeArray();
|
||||
// Verify relationships are loaded
|
||||
$loadedEmployees = $component->get('employees');
|
||||
foreach ($loadedEmployees as $loadedEmployee) {
|
||||
expect($loadedEmployee->relationLoaded('user'))->toBeTrue();
|
||||
expect($loadedEmployee->user->relationLoaded('outlets'))->toBeTrue();
|
||||
}
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user