From 8625a00918f903d74401c7323bc1f87d15650395 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Tue, 2 Jun 2026 16:01:09 +0530 Subject: [PATCH] feat: open help center article from sdk Add window.$chatwoot.openArticle(slug) which opens the widget and navigates the in-widget article viewer to the given help center article. --- app/javascript/entrypoints/sdk.js | 9 +++++++++ app/javascript/widget/App.vue | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/app/javascript/entrypoints/sdk.js b/app/javascript/entrypoints/sdk.js index 6e1639b1c..6e4164605 100755 --- a/app/javascript/entrypoints/sdk.js +++ b/app/javascript/entrypoints/sdk.js @@ -109,6 +109,15 @@ const runSDK = ({ baseUrl, websiteToken }) => { }); }, + openArticle(slug) { + if (!slug) { + throw new Error('Article slug is required'); + } + + IFrameHelper.events.toggleBubble('open'); + IFrameHelper.sendMessage('open-article', { slug }); + }, + setUser(identifier, user) { if (typeof identifier !== 'string' && typeof identifier !== 'number') { throw new Error('Identifier should be a string or a number'); diff --git a/app/javascript/widget/App.vue b/app/javascript/widget/App.vue index 19a33b8a4..8b1d28c61 100755 --- a/app/javascript/widget/App.vue +++ b/app/javascript/widget/App.vue @@ -22,6 +22,10 @@ import { useRouter } from 'vue-router'; import { useAvailability } from 'widget/composables/useAvailability'; import { SDK_SET_BUBBLE_VISIBILITY } from '../shared/constants/sharedFrameEvents'; import { emitter } from 'shared/helpers/mitt'; +import { + getMatchingLocale, + buildArticleViewerLink, +} from 'shared/helpers/portalHelper'; export default { name: 'App', @@ -160,6 +164,21 @@ export default { this.$root.$i18n.locale = localeWithoutVariation; } }, + openArticle(slug) { + const { portal } = window.chatwootWebChannel; + if (!portal || !slug) return; + + const locale = getMatchingLocale( + this.$root.$i18n.locale, + portal.config?.allowed_locales + ); + const link = buildArticleViewerLink({ + link: `hc/${portal.slug}/articles/${slug}`, + locale, + prefersDarkMode: this.prefersDarkMode, + }); + this.router.push({ name: 'article-viewer', query: { link } }); + }, registerUnreadEvents() { emitter.on(ON_AGENT_MESSAGE_RECEIVED, () => { const { name: routeName } = this.$route; @@ -316,6 +335,8 @@ export default { this.setBubbleLabel(); } else if (message.event === 'set-color-scheme') { this.setColorScheme(message.darkMode); + } else if (message.event === 'open-article') { + this.openArticle(message.slug); } else if (message.event === 'toggle-open') { this.$store.dispatch('appConfig/toggleWidgetOpen', message.isOpen);