diff --git a/app/javascript/dashboard/components-next/NewConversation/components/WhatsappTemplateParser.vue b/app/javascript/dashboard/components-next/NewConversation/components/WhatsappTemplateParser.vue index 0dfd53d3a..eb1828257 100644 --- a/app/javascript/dashboard/components-next/NewConversation/components/WhatsappTemplateParser.vue +++ b/app/javascript/dashboard/components-next/NewConversation/components/WhatsappTemplateParser.vue @@ -116,13 +116,25 @@ const generateVariables = () => { }); // Process header variables - if (headerComponent.value?.text) { - const headerVars = headerComponent.value.text.match(/{{([^}]+)}}/g) || []; - headerVars.forEach(variable => { - const key = processVariable(variable); + if (headerComponent.value) { + if (headerComponent.value.text) { + // Text headers with variables + const headerVars = headerComponent.value.text.match(/{{([^}]+)}}/g) || []; + headerVars.forEach(variable => { + const key = processVariable(variable); + if (!allVariables.header) allVariables.header = {}; + allVariables.header[key] = ''; + }); + } else if ( + headerComponent.value.format && + ['IMAGE', 'VIDEO', 'DOCUMENT'].includes(headerComponent.value.format) + ) { + // Media headers need URL input if (!allVariables.header) allVariables.header = {}; - allVariables.header[key] = ''; - }); + allVariables.header.media_url = ''; + allVariables.header.media_type = + headerComponent.value.format.toLowerCase(); + } } // Process footer variables @@ -177,6 +189,44 @@ const validateButtonParameter = (button, index) => { } }; +const getHeaderFieldLabel = key => { + if (key === 'media_url') { + const mediaType = processedParams.value.header?.media_type || 'media'; + return ( + t('WHATSAPP_TEMPLATES.PARSER.MEDIA_URL', { + type: mediaType.toUpperCase(), + }) || `${mediaType.toUpperCase()} URL` + ); + } + return key; +}; + +const getHeaderFieldPlaceholder = key => { + if (key === 'media_url') { + const mediaType = processedParams.value.header?.media_type || 'media'; + switch (mediaType) { + case 'image': + return ( + t('WHATSAPP_TEMPLATES.PARSER.IMAGE_URL_PLACEHOLDER') || + 'Enter image URL (https://example.com/image.jpg)' + ); + case 'video': + return ( + t('WHATSAPP_TEMPLATES.PARSER.VIDEO_URL_PLACEHOLDER') || + 'Enter video URL (https://example.com/video.mp4)' + ); + case 'document': + return ( + t('WHATSAPP_TEMPLATES.PARSER.DOCUMENT_URL_PLACEHOLDER') || + 'Enter document URL (https://example.com/document.pdf)' + ); + default: + return 'Enter media URL'; + } + } + return `Enter ${key} value`; +}; + const sendMessage = async () => { const isValid = await v$.value.$validate(); if (!isValid) return; @@ -243,13 +293,15 @@ onMounted(() => { - {{ key }} + {{ getHeaderFieldLabel(key) }} diff --git a/app/services/whatsapp/template_processor_service.rb b/app/services/whatsapp/template_processor_service.rb index cb8d7b667..f98d2c694 100644 --- a/app/services/whatsapp/template_processor_service.rb +++ b/app/services/whatsapp/template_processor_service.rb @@ -96,8 +96,16 @@ class Whatsapp::TemplateProcessorService # Process header parameters if processed_params['header'].present? - header_params = processed_params['header'].map { |_, value| build_parameter(value) } - components << { type: 'header', parameters: header_params } + header_params = processed_params['header'].filter_map do |key, value| + if key == 'media_url' && processed_params['header']['media_type'].present? + build_media_parameter(value, processed_params['header']['media_type']) + else + build_parameter(value) + end + end + + # Only add header component if we have valid parameters + components << { type: 'header', parameters: header_params } if header_params.present? end # Process footer parameters (rarely used but supported) @@ -216,6 +224,39 @@ class Whatsapp::TemplateProcessorService raise ArgumentError, 'Invalid URL format' end + def build_media_parameter(url, media_type) + return nil if url.blank? + + sanitized_url = sanitize_parameter(url) + validate_url(sanitized_url) + + case media_type.downcase + when 'image' + { + type: 'image', + image: { + link: sanitized_url + } + } + when 'video' + { + type: 'video', + video: { + link: sanitized_url + } + } + when 'document' + { + type: 'document', + document: { + link: sanitized_url + } + } + else + raise ArgumentError, "Unsupported media type: #{media_type}" + end + end + def validated_body_object(template) # we don't care if its not approved template return if template['status'] != 'approved'