293 lines
14 KiB
PHP
293 lines
14 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('content')
|
||
@php
|
||
$reasonLabels = [
|
||
'opt_out' => 'Refus SMS',
|
||
'missing_phone' => 'Sans telephone',
|
||
'invalid' => 'Numero invalide',
|
||
'non_mobile' => 'Non mobile',
|
||
'duplicate' => 'Doublon',
|
||
];
|
||
$summary = $resolution?->summary();
|
||
$showSchedulePanel = old('send_mode', request('send_mode')) === 'scheduled' || old('scheduled_at', request('scheduled_at'));
|
||
@endphp
|
||
|
||
<section class="page-wrap">
|
||
<header class="topbar">
|
||
<div class="title">
|
||
<h1>Composer</h1>
|
||
<p>Selectionner les destinataires et saisir le SMS.</p>
|
||
</div>
|
||
|
||
<div class="actions">
|
||
<a href="{{ route('contacts.index') }}" class="secondary">
|
||
Contacts
|
||
</a>
|
||
</div>
|
||
</header>
|
||
|
||
@error('selection')
|
||
<div class="notice error">
|
||
{{ $message }}
|
||
</div>
|
||
@enderror
|
||
|
||
<form method="POST" action="{{ route('recipients.preview') }}" class="stack">
|
||
@csrf
|
||
<input type="hidden" name="q" value="{{ $search }}">
|
||
|
||
<section class="panel composer-panel" data-recipient-composer data-search-url="{{ route('recipients.search') }}">
|
||
<div class="panel-header">
|
||
<h2>Destination</h2>
|
||
</div>
|
||
|
||
<div class="panel-body stack">
|
||
<div class="field">
|
||
<label for="recipient-composer-input">Pour</label>
|
||
<div class="recipient-composer">
|
||
<div class="recipient-chipbox" data-recipient-selected>
|
||
@foreach ($selectedGroups as $group)
|
||
<span class="recipient-chip group {{ $group->is_favorite ? 'favorite' : '' }}" data-recipient-token data-type="group" data-id="{{ $group->id }}">
|
||
<span>{{ $group->name }}</span>
|
||
<button type="button" data-recipient-remove aria-label="Retirer {{ $group->name }}">×</button>
|
||
<input type="hidden" name="group_ids[]" value="{{ $group->id }}">
|
||
</span>
|
||
@endforeach
|
||
|
||
@foreach ($selectedContacts as $contact)
|
||
<span class="recipient-chip {{ $contact->is_favorite ? 'favorite' : '' }}" data-recipient-token data-type="contact" data-id="{{ $contact->id }}">
|
||
<span>{{ $contact->displayName() }}</span>
|
||
<button type="button" data-recipient-remove aria-label="Retirer {{ $contact->displayName() }}">×</button>
|
||
<input type="hidden" name="contact_ids[]" value="{{ $contact->id }}">
|
||
</span>
|
||
@endforeach
|
||
|
||
<input
|
||
id="recipient-composer-input"
|
||
type="search"
|
||
class="recipient-input"
|
||
autocomplete="off"
|
||
placeholder="Ajouter un contact ou un groupe..."
|
||
data-recipient-input
|
||
>
|
||
</div>
|
||
<div class="recipient-results" data-recipient-results hidden></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="field">
|
||
<label for="message">Message SMS</label>
|
||
<textarea
|
||
id="message"
|
||
name="message"
|
||
rows="5"
|
||
maxlength="612"
|
||
required
|
||
class="textarea"
|
||
data-message-body
|
||
>{{ old('message', request('message')) }}</textarea>
|
||
@error('message')
|
||
<p class="notice error">{{ $message }}</p>
|
||
@enderror
|
||
</div>
|
||
|
||
@if ($smsHeader !== '' || $smsFooter !== '')
|
||
<div
|
||
class="stack-sm"
|
||
data-message-composer
|
||
data-header="{{ e($smsHeader) }}"
|
||
data-footer="{{ e($smsFooter) }}"
|
||
>
|
||
<div class="message-options">
|
||
@if ($smsHeader !== '')
|
||
<input type="hidden" name="include_sms_header" value="0">
|
||
<label class="check-option">
|
||
<input
|
||
name="include_sms_header"
|
||
type="checkbox"
|
||
value="1"
|
||
@checked(old('include_sms_header', $includeSmsHeader ? '1' : '0'))
|
||
data-message-include-header
|
||
>
|
||
Entete
|
||
</label>
|
||
@endif
|
||
|
||
@if ($smsFooter !== '')
|
||
<input type="hidden" name="include_sms_footer" value="0">
|
||
<label class="check-option">
|
||
<input
|
||
name="include_sms_footer"
|
||
type="checkbox"
|
||
value="1"
|
||
@checked(old('include_sms_footer', $includeSmsFooter ? '1' : '0'))
|
||
data-message-include-footer
|
||
>
|
||
Pied
|
||
</label>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="message-preview">
|
||
<strong>SMS complet</strong>
|
||
<pre data-message-preview>{{ $composedMessage }}</pre>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
|
||
<div class="form-grid cols-2" data-schedule-panel @unless ($showSchedulePanel) hidden @endunless>
|
||
<div class="field">
|
||
<label for="scheduled_at">Date et heure d'envoi</label>
|
||
<input
|
||
id="scheduled_at"
|
||
type="datetime-local"
|
||
name="scheduled_at"
|
||
value="{{ old('scheduled_at', request('scheduled_at')) }}"
|
||
class="input"
|
||
data-schedule-input
|
||
>
|
||
@error('scheduled_at')
|
||
<p class="notice error">{{ $message }}</p>
|
||
@enderror
|
||
</div>
|
||
</div>
|
||
|
||
<div class="actions">
|
||
<button type="submit" class="primary" formnovalidate>
|
||
Previsualiser
|
||
</button>
|
||
@if ($resolution && $resolution->recipients !== [])
|
||
<button
|
||
type="submit"
|
||
class="primary"
|
||
name="send_mode"
|
||
value="now"
|
||
formaction="{{ route('sms-campaigns.store') }}"
|
||
onclick="return confirm('Envoyer ce SMS a {{ count($resolution->recipients) }} numero(s) ?')"
|
||
>
|
||
Envoyer {{ count($resolution->recipients) }} SMS
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="secondary"
|
||
data-schedule-toggle
|
||
aria-expanded="{{ $showSchedulePanel ? 'true' : 'false' }}"
|
||
>
|
||
Programmer
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
class="secondary"
|
||
name="send_mode"
|
||
value="scheduled"
|
||
formaction="{{ route('sms-campaigns.store') }}"
|
||
data-schedule-submit
|
||
@unless ($showSchedulePanel) hidden @endunless
|
||
onclick="return confirm('Programmer ce SMS pour {{ count($resolution->recipients) }} numero(s) ?')"
|
||
>
|
||
Confirmer la programmation
|
||
</button>
|
||
@endif
|
||
</div>
|
||
|
||
@if ($resolution)
|
||
<div class="summary-row" aria-label="Resume avant envoi">
|
||
<span class="pill">{{ count($resolution->recipients) }} numeros valides</span>
|
||
<span class="pill">1 SMS / destinataire</span>
|
||
<span class="pill warn">{{ $summary['excluded_total'] }} exclus</span>
|
||
<span class="pill warn">{{ $summary['duplicate'] }} doublons</span>
|
||
</div>
|
||
@endif
|
||
</div>
|
||
</section>
|
||
</form>
|
||
|
||
@if ($resolution)
|
||
<div class="stack">
|
||
<div class="stats-grid five">
|
||
<div class="stat-card">
|
||
<span>Numeros prets</span>
|
||
<strong>{{ $summary['ready_numbers'] }}</strong>
|
||
</div>
|
||
<div class="stat-card">
|
||
<span>Contacts</span>
|
||
<strong>{{ $summary['selected_contacts'] }}</strong>
|
||
</div>
|
||
<div class="stat-card">
|
||
<span>Groupes</span>
|
||
<strong>{{ $summary['selected_groups'] }}</strong>
|
||
</div>
|
||
<div class="stat-card">
|
||
<span>Exclus</span>
|
||
<strong>{{ $summary['excluded_total'] }}</strong>
|
||
</div>
|
||
<div class="stat-card">
|
||
<span>Doublons</span>
|
||
<strong>{{ $summary['duplicate'] }}</strong>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="content-grid">
|
||
<div class="panel">
|
||
<div class="panel-header">
|
||
<h2>Liste finale</h2>
|
||
</div>
|
||
|
||
<div>
|
||
@forelse ($resolution->recipients as $recipient)
|
||
<div class="list-row final-recipient-row">
|
||
<div class="min-w-0">
|
||
<p class="truncate text-strong">{{ $recipient['contact_name'] }}</p>
|
||
<p class="muted truncate text-small">{{ implode(' · ', $recipient['selection']) }}</p>
|
||
</div>
|
||
<p class="text-small text-strong">{{ $recipient['number'] }}</p>
|
||
</div>
|
||
@empty
|
||
<div class="empty-state">Aucun numero pret.</div>
|
||
@endforelse
|
||
</div>
|
||
</div>
|
||
|
||
<div class="panel">
|
||
<div class="panel-header">
|
||
<h2>Ecarts</h2>
|
||
</div>
|
||
|
||
<div>
|
||
@foreach ($reasonLabels as $reason => $label)
|
||
@php($entries = $resolution->excludedByReason($reason))
|
||
@if ($entries !== [])
|
||
<div class="list-row">
|
||
<p class="text-section">{{ $label }} · {{ count($entries) }}</p>
|
||
<div class="stack-sm">
|
||
@foreach ($entries as $entry)
|
||
<div class="text-small">
|
||
<p class="text-strong">{{ $entry['contact_name'] }}</p>
|
||
<p class="muted">
|
||
{{ ucfirst($entry['contact_source'] ?? 'local') }} #{{ $entry['contact_id'] }}
|
||
</p>
|
||
<p class="muted">
|
||
{{ $entry['number'] ?: $entry['raw_number'] ?: 'Aucun numero' }}
|
||
@if (($entry['duplicate_of'] ?? null) !== null)
|
||
· deja retenu pour {{ $entry['duplicate_of'] }}
|
||
@endif
|
||
</p>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
@endif
|
||
@endforeach
|
||
|
||
@if ($resolution->excluded === [])
|
||
<div class="empty-state">Aucun ecart.</div>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endif
|
||
</section>
|
||
@endsection
|