> */ public function searchOrgMembers(int $organizationId, string $ownerRef, string $query = '', int $limit = 20): Collection { $members = Member::owned($ownerRef) ->where('organization_id', $organizationId) ->when($query !== '', function ($q) use ($query) { $q->whereIn('user_ref', User::query() ->where(function ($u) use ($query) { $u->where('name', 'like', "%{$query}%") ->orWhere('email', 'like', "%{$query}%"); }) ->pluck('public_id')); }) ->limit($limit) ->get(); return $members->map(function (Member $member) { $user = User::where('public_id', $member->user_ref)->first(); return [ 'user_ref' => $member->user_ref, 'email' => $user?->email, 'name' => $user?->name ?? $member->user_ref, 'role' => $member->role, 'source' => 'org', ]; })->filter(fn ($c) => filled($c['email'])); } /** * @return Collection> */ public function search(int $organizationId, string $ownerRef, string $query = '', int $limit = 20): Collection { $org = $this->searchOrgMembers($organizationId, $ownerRef, $query, $limit); if ($org->count() >= $limit) { return $org; } $platform = $this->searchPlatformContacts($query, $limit - $org->count()); $emails = $org->pluck('email')->filter()->all(); return $org->merge($platform->reject(fn ($c) => in_array($c['email'], $emails, true)))->take($limit); } /** * @return Collection> */ public function fromGroup(ContactGroup $group): Collection { return $group->members->map(fn ($m) => [ 'email' => $m->email, 'name' => $m->display_name, 'user_ref' => $m->user_ref, 'source' => 'group', ])->filter(fn ($c) => filled($c['email'])); } /** * @return Collection> */ protected function searchPlatformContacts(string $query, int $limit): Collection { $url = rtrim((string) config('identity.api_url'), '/'); $key = config('identity.api_key'); if ($url === '' || $key === '' || $query === '') { return collect(); } try { $response = Http::withToken($key) ->timeout(5) ->get("{$url}/team/search", ['q' => $query, 'limit' => $limit]); if (! $response->successful()) { return collect(); } return collect($response->json('contacts', []))->map(fn ($c) => [ 'user_ref' => $c['public_id'] ?? null, 'email' => $c['email'] ?? null, 'name' => $c['name'] ?? null, 'source' => 'platform', ])->filter(fn ($c) => filled($c['email'])); } catch (\Throwable) { return collect(); } } }