From 7d2fb2b888cf7f9d981ddf54bf2171f7448f4bb9 Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Thu, 18 Sep 2025 14:49:53 +0200 Subject: [PATCH] improve send again texts Signed-off-by: Ronni Skansing --- backend/controller/campaign.go | 2 +- frontend/src/lib/api/api.js | 12 ++- .../src/routes/campaign/[id]/+page.svelte | 77 ++++++++++--------- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/backend/controller/campaign.go b/backend/controller/campaign.go index f5a379a..3e9fb8f 100644 --- a/backend/controller/campaign.go +++ b/backend/controller/campaign.go @@ -866,7 +866,7 @@ func (c *Campaign) SendEmailByCampaignRecipientID(g *gin.Context) { if !ok { return } - // send email + // send message (email or API depending on campaign template configuration) err := c.CampaignService.SendEmailByCampaignRecipientID(g.Request.Context(), session, id) // handle responses if ok := c.handleErrors(g, err); !ok { diff --git a/frontend/src/lib/api/api.js b/frontend/src/lib/api/api.js index 8f232cc..a998180 100644 --- a/frontend/src/lib/api/api.js +++ b/frontend/src/lib/api/api.js @@ -727,7 +727,17 @@ export class API { }, /** - * Send email to campaign recipient + * Send message to campaign recipient (works for both email and API senders) + * + * @param {string} campaignRecipientID + * @returns {Promise} + */ + sendMessage: async (campaignRecipientID) => { + return await postJSON(this.getPath(`/campaign/recipient/${campaignRecipientID}/send`)); + }, + + /** + * Send email to campaign recipient (alias for sendMessage for backward compatibility) * * @param {string} campaignRecipientID * @returns {Promise} diff --git a/frontend/src/routes/campaign/[id]/+page.svelte b/frontend/src/routes/campaign/[id]/+page.svelte index 323a92f..fc0ea29 100644 --- a/frontend/src/routes/campaign/[id]/+page.svelte +++ b/frontend/src/routes/campaign/[id]/+page.svelte @@ -121,8 +121,8 @@ let isRecipientTableLoading = false; let isCloseModalVisible = false; let isAnonymizeModalVisible = false; - let isSendEmailModalVisible = false; - let sendEmailRecipient = null; + let isSendMessageModalVisible = false; + let sendMessageRecipient = null; let lastPoll3399Nano = ''; // hooks @@ -492,47 +492,54 @@ }; /** @param {string} campaignRecipientID @param {Object} recipient */ - const showSendEmailModal = (campaignRecipientID, recipient) => { - sendEmailRecipient = { + const showSendMessageModal = (campaignRecipientID, recipient) => { + sendMessageRecipient = { id: campaignRecipientID, name: `${recipient.firstName || ''} ${recipient.lastName || ''}`.trim(), email: recipient.email }; - isSendEmailModalVisible = true; + isSendMessageModalVisible = true; }; - const closeSendEmailModal = () => { - isSendEmailModalVisible = false; - sendEmailRecipient = null; + const closeSendMessageModal = () => { + isSendMessageModalVisible = false; + sendMessageRecipient = null; }; - const onConfirmSendEmail = async () => { + // helper function to get appropriate messaging based on sender type + const getMessageType = () => { + return campaign.template?.email ? 'email' : 'message'; + }; + + const onConfirmSendMessage = async () => { try { showIsLoading(); // Check if this is a resend before sending - const isResend = campaignRecipients.find((r) => r.id === sendEmailRecipient.id)?.sentAt; - const res = await api.campaign.sendEmail(sendEmailRecipient.id); + const isResend = campaignRecipients.find((r) => r.id === sendMessageRecipient.id)?.sentAt; + const res = await api.campaign.sendMessage(sendMessageRecipient.id); if (!res.success) { throw res.error; } - const campaignType = isSelfManaged ? 'self-managed' : 'scheduled'; - const message = isResend ? `Email sent again successfully` : `Email sent successfully`; + const messageType = getMessageType(); + const message = isResend + ? `${messageType.charAt(0).toUpperCase() + messageType.slice(1)} sent again successfully` + : `${messageType.charAt(0).toUpperCase() + messageType.slice(1)} sent successfully`; addToast(message, 'Success'); await setCampaign(); await getEvents(); await refreshCampaignRecipients(); - closeSendEmailModal(); + closeSendMessageModal(); } catch (e) { - addToast('Failed to send email', 'Error'); - console.error('failed to send email', e); + addToast(`Failed to send ${getMessageType()}`, 'Error'); + console.error(`failed to send ${getMessageType()}`, e); } finally { hideIsLoading(); } }; - // reactive statement to clean up send email modal state when it closes - $: if (!isSendEmailModalVisible && sendEmailRecipient) { - sendEmailRecipient = null; + // reactive statement to clean up send message modal state when it closes + $: if (!isSendMessageModalVisible && sendMessageRecipient) { + sendMessageRecipient = null; } const showCloseCampaignModal = () => { @@ -1459,13 +1466,15 @@ on:click={() => openEventsModal(recp.recipientID)} /> showSendEmailModal(recp.id, recp.recipient)} + : recp.sentAt + ? `Send ${getMessageType()} again (last sent: ${new Date(recp.sentAt).toLocaleDateString()})` + : `Send ${getMessageType()} to recipient`} + on:click={() => showSendMessageModal(recp.id, recp.recipient)} disabled={!!campaign.closedAt || recp.cancelledAt} /> {#if !campaign.sendStartAt} @@ -1756,24 +1765,24 @@
- {#if sendEmailRecipient} - {@const recipient = campaignRecipients.find((r) => r.id === sendEmailRecipient.id)} + {#if sendMessageRecipient} + {@const recipient = campaignRecipients.find((r) => r.id === sendMessageRecipient.id)} {#if recipient}

{recipient.sentAt - ? 'Are you sure you want to send the campaign email again to:' - : 'Are you sure you want to send the campaign email to:'} + ? `Are you sure you want to send the campaign ${getMessageType()} again to:` + : `Are you sure you want to send the campaign ${getMessageType()} to:`}

-

{sendEmailRecipient.name}

-

{sendEmailRecipient.email}

+

{sendMessageRecipient.name}

+

{sendMessageRecipient.email}

- Campaign type: {isSelfManaged ? 'Self-managed' : 'Scheduled'} + Sender type: {campaign.template?.email ? 'Email (SMTP)' : 'API Sender'}

{#if recipient.sentAt}

@@ -1781,9 +1790,7 @@

{/if}
-

- This action will immediately send the email and cannot be undone. -

+

This action will immediately send the message.

{/if} {/if}