view($request, messageComposer: $messageComposer); } public function search(Request $request): JsonResponse { $search = trim((string) $request->query('q', '')); $like = '%'.str_replace(['%', '_'], ['\%', '\_'], $search).'%'; $contacts = Contact::query() ->with('phoneNumbers') ->search($search) ->orderByDesc('is_favorite') ->orderBy('last_name') ->orderBy('first_name') ->limit(10) ->get() ->map(function (Contact $contact): array { $primaryPhone = $contact->phoneNumbers->firstWhere('is_primary', true) ?? $contact->phoneNumbers->first(); return [ 'type' => 'contact', 'id' => $contact->id, 'label' => $contact->displayName(), 'meta' => $primaryPhone?->normalized_number ?: $primaryPhone?->raw_number ?: $contact->email ?: ucfirst($contact->source), 'source' => $contact->source, 'is_favorite' => $contact->is_favorite, ]; }); $groups = ContactGroup::query() ->withCount('contacts') ->when($search !== '', function ($query) use ($like): void { $query->where(function ($query) use ($like): void { $query ->where('name', 'like', $like) ->orWhere('description', 'like', $like); }); }) ->orderByDesc('is_favorite') ->orderBy('name') ->limit(10) ->get() ->map(fn (ContactGroup $group): array => [ 'type' => 'group', 'id' => $group->id, 'label' => $group->name, 'meta' => $group->contacts_count.' contact(s)', 'source' => $group->source, 'is_favorite' => $group->is_favorite, ]); return response()->json([ 'results' => $groups->concat($contacts)->values(), ]); } public function preview(Request $request, RecipientResolver $resolver, SmsMessageComposer $messageComposer): View|RedirectResponse { $validated = $request->validate([ 'q' => ['nullable', 'string', 'max:255'], 'message' => ['nullable', 'string', 'max:612'], 'include_sms_header' => ['nullable', 'boolean'], 'include_sms_footer' => ['nullable', 'boolean'], 'contact_ids' => ['array'], 'contact_ids.*' => ['integer', Rule::exists('contacts', 'id')->whereNull('deleted_at')], 'group_ids' => ['array'], 'group_ids.*' => ['integer', Rule::exists('contact_groups', 'id')->whereNull('deleted_at')], ]); $contactIds = $validated['contact_ids'] ?? []; $groupIds = $validated['group_ids'] ?? []; if ($contactIds === [] && $groupIds === []) { return redirect() ->route('recipients.index', ['q' => $validated['q'] ?? null]) ->withErrors(['selection' => 'Selectionnez au moins un contact ou un groupe.']) ->withInput(); } return $this->view( $request, $resolver->resolve($contactIds, $groupIds), $contactIds, $groupIds, $messageComposer, ); } /** * @param array $selectedContactIds * @param array $selectedGroupIds */ private function view( Request $request, ?RecipientResolutionResult $resolution = null, array $selectedContactIds = [], array $selectedGroupIds = [], ?SmsMessageComposer $messageComposer = null, ): View { $messageComposer ??= app(SmsMessageComposer::class); $messageSettings = $messageComposer->settings(); $oldHeaderChoice = $request->old('include_sms_header'); $oldFooterChoice = $request->old('include_sms_footer'); $hasHeaderChoice = $oldHeaderChoice !== null || $request->has('include_sms_header'); $hasFooterChoice = $oldFooterChoice !== null || $request->has('include_sms_footer'); $includeHeader = $hasHeaderChoice ? filter_var($oldHeaderChoice ?? $request->input('include_sms_header'), FILTER_VALIDATE_BOOLEAN) : $messageSettings['header'] !== ''; $includeFooter = $hasFooterChoice ? filter_var($oldFooterChoice ?? $request->input('include_sms_footer'), FILTER_VALIDATE_BOOLEAN) : $messageSettings['footer'] !== ''; $messageBody = (string) $request->old('message', $request->input('message', '')); $search = trim((string) $request->input('q', '')); $like = '%'.str_replace(['%', '_'], ['\%', '\_'], $search).'%'; $contacts = Contact::query() ->with(['groups', 'phoneNumbers']) ->search($search) ->orderByDesc('is_favorite') ->orderBy('last_name') ->orderBy('first_name') ->limit(50) ->get(); $groups = ContactGroup::query() ->withCount('contacts') ->when($search !== '', function ($query) use ($like): void { $query->where(function ($query) use ($like): void { $query ->where('name', 'like', $like) ->orWhere('description', 'like', $like); }); }) ->orderByDesc('is_favorite') ->orderBy('name') ->limit(50) ->get(); return view('recipients.index', [ 'contacts' => $contacts, 'groups' => $groups, 'search' => $search, 'selectedContactIds' => collect($selectedContactIds)->map(fn (int|string $id): int => (int) $id)->all(), 'selectedGroupIds' => collect($selectedGroupIds)->map(fn (int|string $id): int => (int) $id)->all(), 'selectedContacts' => Contact::query() ->whereKey($selectedContactIds) ->orderBy('last_name') ->orderBy('first_name') ->get(), 'selectedGroups' => ContactGroup::query() ->whereKey($selectedGroupIds) ->orderBy('name') ->get(), 'resolution' => $resolution, 'smsHeader' => $messageSettings['header'], 'smsFooter' => $messageSettings['footer'], 'includeSmsHeader' => $includeHeader, 'includeSmsFooter' => $includeFooter, 'composedMessage' => $messageComposer->compose($messageBody, $includeHeader, $includeFooter), ]); } }