From 64790ea204133d573b441a9456227caaf0881a0c Mon Sep 17 00:00:00 2001 From: Pranav Date: Fri, 1 May 2026 10:53:01 -0700 Subject: [PATCH] fix: Redirect to the conversation URL if custom_view is not available (#14340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an agent shares a conversation link copied from a custom view (e.g. /custom_view/{id}/conversations/{id}), the link previously broke for recipients who didn't have access to that custom view. The conversation now loads regardless — if the custom view isn't available to the recipient, they're redirected to the direct conversation URL. ### How to reproduce 1. As Agent A, open a conversation from inside a personal custom view and copy the URL from the address bar. 2. Share the URL with Agent B who does not have access to that custom view. 3. Before this fix, the link failed to load the conversation. After this fix, Agent B lands on the conversation via the direct URL. ### What changed - Added a beforeEnter guard on the conversations_through_folders route. It checks the user's available conversation custom views (fetching them on demand for deep links), and if the foldersId in the URL isn't among them, redirects to the inbox_conversation route with the same conversation_id. --------- Co-authored-by: iamsivin --- .../conversation/conversation.routes.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js b/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js index 241c70f45..d58617f30 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js +++ b/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js @@ -1,5 +1,6 @@ /* eslint arrow-body-style: 0 */ import { frontendURL } from '../../../helper/URLHelper'; +import store from '../../../store'; import ConversationView from './ConversationView.vue'; const CONVERSATION_PERMISSIONS = [ @@ -10,6 +11,37 @@ const CONVERSATION_PERMISSIONS = [ 'conversation_participating_manage', ]; +const isFolderAvailable = async folderId => { + let folders = store.getters['customViews/getConversationCustomViews']; + if (!folders.length) { + await store.dispatch('customViews/get', 'conversation'); + folders = store.getters['customViews/getConversationCustomViews']; + } + return folders.some(folder => folder.id === Number(folderId)); +}; + +const redirectFolderListIfUnavailable = async (to, _from, next) => { + if (await isFolderAvailable(to.params.id)) { + next(); + return; + } + next({ name: 'home', params: { accountId: to.params.accountId } }); +}; + +const redirectFolderConversationIfUnavailable = async (to, _from, next) => { + if (await isFolderAvailable(to.params.id)) { + next(); + return; + } + next({ + name: 'inbox_conversation', + params: { + accountId: to.params.accountId, + conversation_id: to.params.conversation_id, + }, + }); +}; + export default { routes: [ { @@ -113,6 +145,7 @@ export default { meta: { permissions: CONVERSATION_PERMISSIONS, }, + beforeEnter: redirectFolderListIfUnavailable, component: ConversationView, props: route => ({ foldersId: route.params.id }), }, @@ -125,6 +158,7 @@ export default { permissions: CONVERSATION_PERMISSIONS, }, component: ConversationView, + beforeEnter: redirectFolderConversationIfUnavailable, props: route => ({ conversationId: route.params.conversation_id, foldersId: route.params.id,