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'