diff --git a/app/javascript/dashboard/components-next/message/Message.vue b/app/javascript/dashboard/components-next/message/Message.vue index f6dd35985..14efa4ab8 100644 --- a/app/javascript/dashboard/components-next/message/Message.vue +++ b/app/javascript/dashboard/components-next/message/Message.vue @@ -42,6 +42,7 @@ import CSATBubble from './bubbles/CSAT.vue'; import FormBubble from './bubbles/Form.vue'; import VoiceCallBubble from './bubbles/VoiceCall.vue'; import WhatsappFlowResponseBubble from './bubbles/WhatsappFlowResponse.vue'; +import WhatsappReferral from './bubbles/Text/WhatsappReferral.vue'; import MessageError from './MessageError.vue'; import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu.vue'; @@ -370,6 +371,12 @@ const isMessageDeleted = computed(() => { return props.contentAttributes?.deleted; }); +const shouldShowWhatsappReferral = computed( + () => + variant.value === MESSAGE_VARIANTS.USER && + !!props.contentAttributes?.referral +); + const payloadForContextMenu = computed(() => { return { id: props.id, @@ -426,6 +433,7 @@ const shouldRenderMessage = computed(() => { isUnsupported || isAnIntegrationMessage || hasWhatsappFlowResponse || + shouldShowWhatsappReferral.value || isFailedMessage || hasExternalError ); @@ -580,9 +588,14 @@ provideMessageContext({ :class="{ 'ltr:ml-8 rtl:mr-8 justify-end': orientation === ORIENTATION.RIGHT, 'ltr:mr-8 rtl:ml-8': orientation === ORIENTATION.LEFT, + 'flex-col items-start gap-2': shouldShowWhatsappReferral, }" @contextmenu="openContextMenu($event)" > + +import { computed, ref } from 'vue'; +import { useI18n } from 'vue-i18n'; +import Icon from 'next/icon/Icon.vue'; + +const props = defineProps({ + referral: { type: Object, required: true }, +}); + +const { t } = useI18n(); +const hasMediaError = ref(false); + +const safeUrl = value => { + if (!value) return ''; + + try { + const url = new URL(value); + return ['http:', 'https:'].includes(url.protocol) ? url.toString() : ''; + } catch { + return ''; + } +}; + +const sourceUrl = computed(() => safeUrl(props.referral.sourceUrl)); +const mediaUrl = computed(() => + safeUrl( + props.referral.thumbnailUrl || + props.referral.imageUrl || + props.referral.mediaUrl || + props.referral.videoUrl + ) +); +const showMedia = computed(() => mediaUrl.value && !hasMediaError.value); +const isVideo = computed( + () => + props.referral.mediaType === 'video' || + props.referral.mediaContentType?.startsWith('video/') +); +const renderVideo = computed( + () => isVideo.value && !props.referral.thumbnailUrl +); + +const handleMediaError = () => { + hasMediaError.value = true; +}; + + + diff --git a/app/javascript/dashboard/components-next/message/provider.js b/app/javascript/dashboard/components-next/message/provider.js index a8523296b..7c4dc8b3e 100644 --- a/app/javascript/dashboard/components-next/message/provider.js +++ b/app/javascript/dashboard/components-next/message/provider.js @@ -68,6 +68,16 @@ const MessageControl = Symbol('MessageControl'); * @property {string|null} [bccEmail] - BCC email addresses * @property {Object} [whatsappFlowResponse] - WhatsApp Flow response metadata * @property {Record|string} [whatsappFlowResponse.responseJson] - Structured fields or the raw response submitted by the contact + * @property {Object} [referral] - WhatsApp click-to-chat ad metadata + * @property {string} [referral.sourceUrl] - URL of the originating ad + * @property {string} [referral.headline] - Headline of the originating ad + * @property {string} [referral.body] - Body copy of the originating ad + * @property {string} [referral.mediaType] - Media type of the originating ad + * @property {string} [referral.thumbnailUrl] - Thumbnail of the originating ad + * @property {string} [referral.imageUrl] - Image URL of a Cloud API referral + * @property {string} [referral.videoUrl] - Video URL of a Cloud API referral + * @property {string} [referral.mediaUrl] - Media URL of a Twilio referral + * @property {string} [referral.mediaContentType] - Media content type of a Twilio referral */ /** diff --git a/app/javascript/dashboard/i18n/locale/en/conversation.json b/app/javascript/dashboard/i18n/locale/en/conversation.json index be759c7c4..4620fc18e 100644 --- a/app/javascript/dashboard/i18n/locale/en/conversation.json +++ b/app/javascript/dashboard/i18n/locale/en/conversation.json @@ -67,6 +67,9 @@ "UNSUPPORTED_MESSAGE_TIKTOK": "This message is unsupported. You can view this message on the TikTok app.", "UNSUPPORTED_MESSAGE_WHATSAPP": "This message is unsupported. You can view this message on the WhatsApp app.", "WHATSAPP_FLOW_RESPONSE": "Submitted a flow response", + "WHATSAPP_REFERRAL": { + "AD": "Ad" + }, "SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "NO_RESPONSE": "No response",