187 lines
7.3 KiB
PHP
187 lines
7.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Contact;
|
|
use App\Models\ContactGroup;
|
|
use App\Services\Recipients\RecipientResolutionResult;
|
|
use App\Services\Recipients\RecipientResolver;
|
|
use App\Services\Sms\SmsMessageComposer;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class RecipientSelectionController extends Controller
|
|
{
|
|
public function index(Request $request, SmsMessageComposer $messageComposer): View
|
|
{
|
|
return $this->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<int, int|string> $selectedContactIds
|
|
* @param array<int, int|string> $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),
|
|
]);
|
|
}
|
|
}
|