diff --git a/static/app/utils/intercom.tsx b/static/app/utils/intercom.tsx index b2147227a2c80f..e0f519cf120fd4 100644 --- a/static/app/utils/intercom.tsx +++ b/static/app/utils/intercom.tsx @@ -24,6 +24,7 @@ interface IntercomJwtResponse { let hasBooted = false; let bootPromise: Promise | null = null; +let bootedOrgSlug: string | null = null; /** * Initialize Intercom with identity verification. @@ -69,6 +70,7 @@ async function initIntercom(orgSlug: string): Promise { }); hasBooted = true; + bootedOrgSlug = orgSlug; } catch (error) { // Reset so user can retry on next click bootPromise = null; @@ -79,11 +81,34 @@ async function initIntercom(orgSlug: string): Promise { return bootPromise; } +/** + * Shutdown Intercom and clear session data. + * Call this when user logs out or switches organizations. + */ +export async function shutdownIntercom(): Promise { + if (!hasBooted) { + return; + } + + const {shutdown} = await import('@intercom/messenger-js-sdk'); + shutdown(); + + hasBooted = false; + bootPromise = null; + bootedOrgSlug = null; +} + /** * Show the Intercom Messenger. * Lazily initializes Intercom on first call. + * If already booted for a different org, shuts down first and re-initializes. */ export async function showIntercom(orgSlug: string): Promise { + // If booted for a different org, shutdown first to re-initialize with new org context + if (hasBooted && bootedOrgSlug !== orgSlug) { + await shutdownIntercom(); + } + await initIntercom(orgSlug); const {show} = await import('@intercom/messenger-js-sdk'); show(); diff --git a/static/app/views/organizationContext.spec.tsx b/static/app/views/organizationContext.spec.tsx index 8794382d8d3113..6c6d409e5a8853 100644 --- a/static/app/views/organizationContext.spec.tsx +++ b/static/app/views/organizationContext.spec.tsx @@ -12,6 +12,7 @@ import {OrganizationStore} from 'sentry/stores/organizationStore'; import {ProjectsStore} from 'sentry/stores/projectsStore'; import {TeamStore} from 'sentry/stores/teamStore'; import type {Organization} from 'sentry/types/organization'; +import * as intercom from 'sentry/utils/intercom'; import {useOrganization} from 'sentry/utils/useOrganization'; import {OrganizationContextProvider} from './organizationContext'; @@ -114,6 +115,7 @@ describe('OrganizationContext', () => { const {orgMock, projectMock, teamMock} = setupOrgMocks(anotherOrg); const switchOrganization = jest.spyOn(orgsActionCreators, 'switchOrganization'); + const shutdownIntercom = jest.spyOn(intercom, 'shutdownIntercom'); // re-render with another-org testRouter.navigate(`/organizations/${anotherOrg.slug}/`); @@ -123,6 +125,7 @@ describe('OrganizationContext', () => { expect(projectMock).toHaveBeenCalled(); expect(teamMock).toHaveBeenCalled(); expect(switchOrganization).toHaveBeenCalled(); + expect(shutdownIntercom).toHaveBeenCalled(); expect(JSON.stringify(OrganizationStore.getState().organization)).toEqual( JSON.stringify(anotherOrg) ); diff --git a/static/app/views/organizationContext.tsx b/static/app/views/organizationContext.tsx index 5c0f85e1b07e04..a6f72d3afcde9e 100644 --- a/static/app/views/organizationContext.tsx +++ b/static/app/views/organizationContext.tsx @@ -18,6 +18,7 @@ import {TeamStore} from 'sentry/stores/teamStore'; import {useLegacyStore} from 'sentry/stores/useLegacyStore'; import type {Organization} from 'sentry/types/organization'; import type {User} from 'sentry/types/user'; +import {shutdownIntercom} from 'sentry/utils/intercom'; import {useParams} from 'sentry/utils/useParams'; interface Props { @@ -147,6 +148,8 @@ export function OrganizationContextProvider({children}: Props) { // Also avoid: org1 -> undefined -> org1 if (lastOrgId.current) { switchOrganization(); + // Shutdown Intercom so it re-initializes with new org context on next use + shutdownIntercom(); } lastOrgId.current = orgSlug;