diff --git a/app/Http/Controllers/Frontdesk/EmployeeController.php b/app/Http/Controllers/Frontdesk/EmployeeController.php index 488547a..845a724 100644 --- a/app/Http/Controllers/Frontdesk/EmployeeController.php +++ b/app/Http/Controllers/Frontdesk/EmployeeController.php @@ -8,11 +8,14 @@ use App\Models\Branch; use App\Models\Employee; use App\Models\EmployeePresenceEvent; use App\Models\Host; +use App\Models\Member; +use App\Models\User; use App\Services\Frontdesk\EmployeePresenceService; use App\Services\Frontdesk\QrCodeService; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Carbon; +use Illuminate\Validation\Rule; use Illuminate\View\View; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -44,6 +47,7 @@ class EmployeeController extends Controller 'organization' => $organization, 'branches' => $this->branches($request, $organization->id), 'hosts' => $this->hosts($request, $organization->id), + 'linkableUsers' => $this->linkableUsers($request, $organization->id), ]); } @@ -52,7 +56,7 @@ class EmployeeController extends Controller $this->authorizeAbility($request, 'employees.manage'); $organization = $this->organization($request); - $validated = $this->validatedEmployee($request); + $validated = $this->validatedEmployee($request, $organization->id); $pin = $validated['pin']; unset($validated['pin']); @@ -77,6 +81,7 @@ class EmployeeController extends Controller 'employee' => $employee->load('presence'), 'branches' => $this->branches($request, $employee->organization_id), 'hosts' => $this->hosts($request, $employee->organization_id), + 'linkableUsers' => $this->linkableUsers($request, $employee->organization_id, $employee), ]); } @@ -85,7 +90,7 @@ class EmployeeController extends Controller $this->authorizeAbility($request, 'employees.manage'); $this->authorizeOwner($request, $employee); - $validated = $this->validatedEmployee($request, updating: true); + $validated = $this->validatedEmployee($request, $employee->organization_id, updating: true, employee: $employee); $payload = $this->employeePayload($validated); if (! empty($validated['pin'])) { @@ -277,12 +282,17 @@ class EmployeeController extends Controller } /** @return array */ - protected function validatedEmployee(Request $request, bool $updating = false): array + protected function validatedEmployee(Request $request, int $organizationId, bool $updating = false, ?Employee $employee = null): array { $pinRules = $updating ? ['nullable', 'string', 'regex:/^\d{4,6}$/'] : ['required', 'string', 'regex:/^\d{4,6}$/']; + $linkableRefs = collect($this->linkableUsers($request, $organizationId, $employee)) + ->reject(fn (array $user) => $user['taken']) + ->pluck('user_ref') + ->all(); + return $request->validate([ 'employee_code' => ['required', 'string', 'max:32'], 'full_name' => ['required', 'string', 'max:255'], @@ -292,10 +302,82 @@ class EmployeeController extends Controller 'pin' => $pinRules, 'branch_id' => ['nullable', 'integer'], 'host_id' => ['nullable', 'integer'], - 'user_ref' => ['nullable', 'string', 'max:64'], + 'user_ref' => [ + 'nullable', + 'string', + 'max:64', + Rule::when( + filled($request->input('user_ref')), + [Rule::in($linkableRefs)] + ), + ], ]); } + /** + * Ladill users that can be linked to an employee (team members and linked hosts). + * + * @return list + */ + protected function linkableUsers(Request $request, int $organizationId, ?Employee $employee = null): array + { + $ownerRef = $this->ownerRef($request); + + $refs = collect() + ->merge( + Member::owned($ownerRef) + ->where('organization_id', $organizationId) + ->pluck('user_ref') + ) + ->merge( + Host::owned($ownerRef) + ->where('organization_id', $organizationId) + ->whereNotNull('user_ref') + ->pluck('user_ref') + ) + ->merge( + Employee::owned($ownerRef) + ->where('organization_id', $organizationId) + ->whereNotNull('user_ref') + ->pluck('user_ref') + ); + + if ($employee?->user_ref) { + $refs->push($employee->user_ref); + } + + $refs = $refs->filter()->unique()->values(); + + $users = User::query() + ->whereIn('public_id', $refs) + ->get(['public_id', 'name', 'email']) + ->keyBy('public_id'); + + $takenRefs = Employee::owned($ownerRef) + ->where('organization_id', $organizationId) + ->whereNotNull('user_ref') + ->when($employee, fn ($query) => $query->where('id', '!=', $employee->id)) + ->pluck('user_ref') + ->flip(); + + return $refs + ->map(function (string $ref) use ($users, $takenRefs, $employee) { + $user = $users->get($ref); + $label = $user + ? trim($user->name.' ยท '.$user->email) + : $ref; + + return [ + 'user_ref' => $ref, + 'label' => $label, + 'taken' => $takenRefs->has($ref) && $employee?->user_ref !== $ref, + ]; + }) + ->sortBy('label', SORT_NATURAL | SORT_FLAG_CASE) + ->values() + ->all(); + } + protected function employeePayload(array $validated): array { $payload = $validated; diff --git a/resources/views/frontdesk/employees/create.blade.php b/resources/views/frontdesk/employees/create.blade.php index 14fc6d2..ac25998 100644 --- a/resources/views/frontdesk/employees/create.blade.php +++ b/resources/views/frontdesk/employees/create.blade.php @@ -51,10 +51,7 @@

When stepped out, linked hosts show as unavailable to visitors.

-
- - -
+ @include('frontdesk.employees.partials.user-ref-select', ['selectedUserRef' => old('user_ref')]) diff --git a/resources/views/frontdesk/employees/edit.blade.php b/resources/views/frontdesk/employees/edit.blade.php index 96220b9..65154e5 100644 --- a/resources/views/frontdesk/employees/edit.blade.php +++ b/resources/views/frontdesk/employees/edit.blade.php @@ -49,11 +49,7 @@ @endforeach -
- - -

Enables the My presence portal for this employee.

-
+ @include('frontdesk.employees.partials.user-ref-select', ['selectedUserRef' => old('user_ref', $employee->user_ref)])