diff --git a/app/helpers/portal_helper.rb b/app/helpers/portal_helper.rb index 3ed303556..e98f0a72d 100644 --- a/app/helpers/portal_helper.rb +++ b/app/helpers/portal_helper.rb @@ -74,6 +74,17 @@ module PortalHelper end end + def generate_portal_brand_url(brand_url, referer) + url = URI.parse(brand_url.to_s) + query_params = Rack::Utils.parse_query(url.query) + query_params['utm_medium'] = 'helpcenter' + query_params['utm_campaign'] = 'branding' + query_params['utm_source'] = URI.parse(referer).host if referer.present? && referer.match?(URI::DEFAULT_PARSER.make_regexp) + + url.query = query_params.to_query + url.to_s + end + def render_category_content(content) ChatwootMarkdownRenderer.new(content).render_markdown_to_plain_text end diff --git a/app/javascript/shared/components/Branding.vue b/app/javascript/shared/components/Branding.vue index 9ca976d80..2f1a8d5d0 100644 --- a/app/javascript/shared/components/Branding.vue +++ b/app/javascript/shared/components/Branding.vue @@ -33,13 +33,15 @@ export default { brandRedirectURL() { try { const referrerHost = this.$store.getters['appConfig/getReferrerHost']; - const baseURL = `${this.globalConfig.widgetBrandURL}?utm_source=${ - referrerHost ? 'widget_branding' : 'survey_branding' - }`; + const url = new URL(this.globalConfig.widgetBrandURL); if (referrerHost) { - return `${baseURL}&utm_referrer=${referrerHost}`; + url.searchParams.set('utm_source', referrerHost); + url.searchParams.set('utm_medium', 'widget'); + } else { + url.searchParams.set('utm_medium', 'survey'); } - return baseURL; + url.searchParams.set('utm_campaign', 'branding'); + return url.toString(); } catch (e) { // Suppressing the error as getter is not defined in some cases } diff --git a/app/views/public/api/v1/portals/_footer.html.erb b/app/views/public/api/v1/portals/_footer.html.erb index 8de87b8f2..bfba6235b 100644 --- a/app/views/public/api/v1/portals/_footer.html.erb +++ b/app/views/public/api/v1/portals/_footer.html.erb @@ -8,12 +8,12 @@ alt="<%= @global_config['BRAND_NAME'] %>" src="<%= @global_config['LOGO_THUMBNAIL'] %>" /> -
- <%= I18n.t('public_portal.footer.made_with') %> - - <%= @global_config['BRAND_NAME'] %> - -
++ <%= I18n.t('public_portal.footer.made_with') %> + + <%= @global_config['BRAND_NAME'] %> + +
diff --git a/spec/helpers/portal_helper_spec.rb b/spec/helpers/portal_helper_spec.rb index 241b4c6dd..d55c83be7 100644 --- a/spec/helpers/portal_helper_spec.rb +++ b/spec/helpers/portal_helper_spec.rb @@ -291,4 +291,40 @@ describe PortalHelper do end end end + + describe '#generate_portal_brand_url' do + it 'builds URL with UTM params and referer host as source (happy path)' do + result = helper.generate_portal_brand_url('https://brand.example.com', 'https://app.chatwoot.com/some/page') + uri = URI.parse(result) + params = Rack::Utils.parse_query(uri.query) + expect(uri.scheme).to eq('https') + expect(uri.host).to eq('brand.example.com') + expect(params['utm_medium']).to eq('helpcenter') + expect(params['utm_campaign']).to eq('branding') + expect(params['utm_source']).to eq('app.chatwoot.com') + end + + it 'returns utm string when brand_url is nil or empty' do + expect(helper.generate_portal_brand_url(nil, + 'https://app.chatwoot.com')).to eq( + '?utm_campaign=branding&utm_medium=helpcenter&utm_source=app.chatwoot.com' + ) + expect(helper.generate_portal_brand_url('', + 'https://app.chatwoot.com')).to eq( + '?utm_campaign=branding&utm_medium=helpcenter&utm_source=app.chatwoot.com' + ) + end + + it 'omits utm_source when referer is nil or invalid' do + r1 = helper.generate_portal_brand_url('https://brand.example.com', nil) + p1 = Rack::Utils.parse_query(URI.parse(r1).query) + expect(p1.key?('utm_source')).to be(false) + + r2 = helper.generate_portal_brand_url('https://brand.example.com', '::not-a-valid-url') + p2 = Rack::Utils.parse_query(URI.parse(r2).query) + expect(p2.key?('utm_source')).to be(false) + expect(p2['utm_medium']).to eq('helpcenter') + expect(p2['utm_campaign']).to eq('branding') + end + end end