Events: wire mass-send button + confirmation dialog into the UI

Frontend half of the campaign-integrated mass send: an "Envoyer à N
destinataire(s)" button in the send dialog's mass tab, gated behind a
confirmation dialog that shows the exact recipient count and channel before
firing. On success, links to the created campaign in /campaigns for tracking.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-07-09 12:41:34 -04:00
parent 929ef73d93
commit cab1a9c94a

View File

@ -371,15 +371,18 @@
<q-btn unelevated no-caps color="primary" icon="playlist_add" label="Ajouter le CSV à la liste" :disable="!audCsvText" :loading="listBusy" @click="addCsvToList" /> <q-btn unelevated no-caps color="primary" icon="playlist_add" label="Ajouter le CSV à la liste" :disable="!audCsvText" :loading="listBusy" @click="addCsvToList" />
</div> </div>
<q-banner dense rounded class="bg-grey-2 text-grey-8"> <q-separator class="q-my-sm" />
<template #avatar><q-icon name="lock" color="grey-7" /></template> <q-banner dense rounded class="bg-blue-1 text-blue-10">
L'envoi réel (création de la campagne + envoi suivi) est la dernière étape à activer — rien n'est envoyé aux clients ici. <template #avatar><q-icon name="insights" color="blue-8" /></template>
L'envoi crée une campagne : suivi ouvertures/clics (Mailjet), statut par destinataire et rapport dans <a class="text-primary cursor-pointer text-weight-medium" @click="goCampaigns">Campagnes</a>.
</q-banner> </q-banner>
</q-card-section> </q-card-section>
<q-card-actions align="right"> <q-card-actions align="right">
<q-btn flat no-caps label="Fermer" v-close-popup /> <q-btn flat no-caps label="Fermer" v-close-popup />
<q-btn v-if="sendMode === 'test'" unelevated no-caps color="primary" icon="send" label="Envoyer un test" :loading="sending" @click="sendTestNow" /> <q-btn v-if="sendMode === 'test'" unelevated no-caps color="primary" icon="send" label="Envoyer un test" :loading="sending" @click="sendTestNow" />
<q-btn v-else unelevated no-caps color="negative" icon="send" :disable="!mainList.count || sendingMass" :loading="sendingMass"
:label="mainList.count ? `Envoyer à ${mainList.count} destinataire(s)` : 'Liste vide'" @click="confirmMassSend" />
</q-card-actions> </q-card-actions>
</q-card> </q-card>
</q-dialog> </q-dialog>
@ -777,6 +780,29 @@ function clearList () {
catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { listBusy.value = false } catch (e) { $q.notify({ type: 'negative', message: e.message }) } finally { listBusy.value = false }
}) })
} }
function goCampaigns () { window.location.hash = '#/campaigns' }
const sendingMass = ref(false)
function confirmMassSend () {
const n = mainList.value.count
if (!n) return
const chan = sendChannel.value === 'gmail' ? 'Gmail' : 'Mailjet'
$q.dialog({
title: "Envoyer l'invitation",
message: `Envoyer un vrai courriel d'invitation à <b>${n}</b> destinataire(s) via <b>${chan}</b> ?<br>Chacun reçoit un lien RSVP personnel. Cette action est irréversible.`,
html: true,
cancel: { label: 'Annuler', flat: true, noCaps: true },
ok: { label: `Envoyer à ${n}`, color: 'negative', unelevated: true, noCaps: true },
persistent: true,
}).onOk(async () => {
sendingMass.value = true
try {
const r = await sendInvite(eventId.value, { mass: true, channel: sendChannel.value })
$q.notify({ type: 'positive', message: `Envoi lancé à ${r.count} destinataire(s)`, caption: 'Suivi dans Campagnes', icon: 'send', timeout: 7000, actions: [{ label: 'Ouvrir Campagnes', color: 'white', handler: goCampaigns }] })
showSend.value = false
load()
} catch (e) { $q.notify({ type: 'negative', message: 'Échec du lancement : ' + e.message }) } finally { sendingMass.value = false }
})
}
async function sendTestNow () { async function sendTestNow () {
const em = (testEmail.value || '').trim() const em = (testEmail.value || '').trim()
if (!em) { $q.notify({ type: 'warning', message: 'Entrez un courriel de test' }); return } if (!em) { $q.notify({ type: 'warning', message: 'Entrez un courriel de test' }); return }