diff --git a/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue b/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue index c87d279..8037055 100644 --- a/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue +++ b/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue @@ -3,6 +3,14 @@
Nouvelle campagne
+ + + + S'ouvre dans un nouvel onglet — tes fichiers uploadés restent intacts ici +
@@ -212,10 +220,27 @@ + - + + + Voir le rendu du courriel avec les vraies données du destinataire #1 (n'envoie rien) + + + Ouvre l'éditeur dans un nouvel onglet — ton import reste ici intact + + + Va à l'étape de confirmation finale. L'envoi ne démarre qu'au clic sur "Lancer l'envoi" de l'étape 3. + @@ -236,19 +261,52 @@ Durée estimée≈ {{ estimatedMinutes }} min - - L'envoi démarre dès que vous cliquez ci-dessous. - Vous serez redirigé vers la page de progression en temps réel. + + Confirmation finale. + L'envoi démarre dès le clic sur "Lancer l'envoi maintenant". + Tu seras redirigé vers la page de progression temps réel. - - + + + + + + + + + + + + Aperçu du courriel + + · destinataire #{{ previewRecipient.row_index }} {{ previewRecipient.firstname }} {{ previewRecipient.lastname }} + + + + + Éditer dans un nouvel onglet + + + + + Rendu en cours… + + + + + + @@ -256,7 +314,7 @@ import { ref, computed } from 'vue' import { useRouter } from 'vue-router' import { useQuasar } from 'quasar' -import { parseCsvs, createCampaign, sendCampaign } from 'src/api/campaigns' +import { parseCsvs, createCampaign, sendCampaign, previewTemplate } from 'src/api/campaigns' const $q = useQuasar() const router = useRouter() @@ -344,6 +402,81 @@ function shortenUrl (u) { return u.replace(/^https?:\/\//, '').slice(0, 28) + (u.length > 35 ? '…' : '') } +// ── Preview dialog ────────────────────────────────────────────────────────── +// Renders the email through the hub's /campaigns/templates/:name/preview +// endpoint, using the first sendable recipient's data + the current campaign +// params. Non-destructive — no emails are fired by this action. +const previewOpen = ref(false) +const previewLoading = ref(false) +const previewHtmlContent = ref('') +const previewLang = ref('fr') +const previewRecipient = ref(null) + +// First recipient that's actually going to be sent — used as the preview +// sample so the user sees real data, not synthetic placeholders. +const firstPreviewable = computed(() => + recipients.value.find(r => !r.excluded && r.gift_url) || null +) + +// Link to the template editor for the relevant language. Always opens +// in a new tab so the user's in-progress wizard state is preserved. +const editorHref = computed(() => + `/ops/#/campaigns/templates/gift-email-${previewLang.value}` +) + +async function openPreview () { + const r = firstPreviewable.value + if (!r) return + previewRecipient.value = r + // Default preview language to the recipient's actual language so the user + // first sees what THIS recipient will receive + previewLang.value = (r.language || 'fr').toLowerCase().split('-')[0] + previewOpen.value = true + await renderPreview() +} + +async function renderPreview () { + if (!previewRecipient.value) return + previewLoading.value = true + try { + const r = previewRecipient.value + const vars = { + firstname: r.firstname || (previewLang.value === 'en' ? 'dear customer' : 'cher client'), + lastname: r.lastname || '', + email: r.email, + description: r.civic_address || '', + gift_url: r.gift_url, + amount: params.value.amount, + expiry: params.value.expiry, + commitment_months: params.value.commitment_months, + year: new Date().getFullYear(), + } + const res = await previewTemplate(`gift-email-${previewLang.value}`, { vars }) + previewHtmlContent.value = res.rendered || '' + } catch (e) { + $q.notify({ type: 'negative', message: 'Aperçu impossible: ' + e.message }) + } finally { + previewLoading.value = false + } +} + +// Wrapper around launchSend that confirms one last time before firing. The +// Step 3 page is already a "confirmation step", but this dialog adds one +// final friction so accidental clicks don't fire 200 emails. +function confirmAndLaunch () { + $q.dialog({ + title: 'Envoyer maintenant ?', + message: `Cette action enverra ${sendableCount.value} courriel(s) + via Mailjet immédiatement. Pas annulable une fois démarré.`, + html: true, + persistent: true, + ok: { label: 'Oui, envoyer', color: 'negative', icon: 'send', unelevated: true }, + cancel: { label: 'Annuler', flat: true }, + }).onOk(() => { + launchSend() + }) +} + function readFile (file) { return new Promise((resolve, reject) => { const r = new FileReader()