feat: add Intercom messenger integration to web-roo-code

This commit is contained in:
Roo Code 2025-12-11 12:23:46 +00:00
parent a1d3a43aa5
commit cd3ef6f003
5 changed files with 114 additions and 10 deletions

View file

@ -2,6 +2,10 @@
# Replace these values with your actual PostHog API key and host
NEXT_PUBLIC_POSTHOG_KEY=your_posthog_api_key_here
# Intercom Messenger Configuration
# Replace this with your actual Intercom App ID
NEXT_PUBLIC_INTERCOM_APP_ID=your_intercom_app_id_here
# Basin Form Endpoint for Static Form Submissions
# Replace this with your actual Basin form endpoint (e.g., https://usebasin.com/f/your-form-id)
NEXT_PUBLIC_BASIN_ENDPOINT=https://usebasin.com/f/your-form-id-here

View file

@ -1 +1,2 @@
export { IntercomProvider } from "./intercom-provider"
export { Providers } from "./providers"

View file

@ -0,0 +1,96 @@
"use client"
import { useEffect } from "react"
import { hasConsent, onConsentChange } from "@/lib/analytics/consent-manager"
// Intercom interface - it's a callable function with overloads
interface IntercomInstance {
(command: "boot", config: Record<string, unknown>): void
(command: "shutdown"): void
(command: "update", config?: Record<string, unknown>): void
(command: "show"): void
(command: "hide"): void
(command: "showMessages"): void
(command: "showNewMessage", message?: string): void
(command: "onHide", callback: () => void): void
(command: "onShow", callback: () => void): void
(command: "onUnreadCountChange", callback: (unreadCount: number) => void): void
}
declare global {
interface Window {
Intercom?: IntercomInstance
intercomSettings?: Record<string, unknown>
}
}
export function IntercomProvider({ children }: { children: React.ReactNode }) {
const appId = process.env.NEXT_PUBLIC_INTERCOM_APP_ID
useEffect(() => {
// Only initialize if Intercom App ID is configured
if (!appId) {
return
}
// Check initial consent status
const consentGiven = hasConsent()
if (consentGiven) {
loadIntercom(appId)
}
// Listen for consent changes
const cleanup = onConsentChange((granted) => {
if (granted) {
loadIntercom(appId)
} else {
shutdownIntercom()
}
})
return () => {
cleanup()
shutdownIntercom()
}
}, [appId])
const loadIntercom = (appId: string) => {
if (typeof window === "undefined") return
// Skip if already loaded
if (window.Intercom) {
window.Intercom("update")
return
}
// Set up Intercom settings
window.intercomSettings = {
app_id: appId,
alignment: "right",
horizontal_padding: 20,
vertical_padding: 20,
}
// Load Intercom script
const script = document.createElement("script")
script.async = true
script.src = `https://widget.intercom.io/widget/${appId}`
script.onload = () => {
if (window.Intercom) {
window.Intercom("boot", window.intercomSettings || {})
}
}
document.head.appendChild(script)
}
const shutdownIntercom = () => {
if (typeof window !== "undefined" && window.Intercom) {
window.Intercom("shutdown")
}
}
return <>{children}</>
}

View file

@ -4,6 +4,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { ThemeProvider } from "next-themes"
import { GoogleTagManagerProvider } from "./google-tag-manager-provider"
import { IntercomProvider } from "./intercom-provider"
import { PostHogProvider } from "./posthog-provider"
const queryClient = new QueryClient()
@ -12,11 +13,13 @@ export const Providers = ({ children }: { children: React.ReactNode }) => {
return (
<QueryClientProvider client={queryClient}>
<GoogleTagManagerProvider>
<PostHogProvider>
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem={false}>
{children}
</ThemeProvider>
</PostHogProvider>
<IntercomProvider>
<PostHogProvider>
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem={false}>
{children}
</ThemeProvider>
</PostHogProvider>
</IntercomProvider>
</GoogleTagManagerProvider>
</QueryClientProvider>
)

View file

@ -21,10 +21,10 @@ export function hasConsent(): boolean {
/**
* Dispatch a consent change event
*/
export function dispatchConsentEvent(consented: boolean): void {
export function dispatchConsentEvent(granted: boolean): void {
if (typeof window !== "undefined") {
const event = new CustomEvent(CONSENT_EVENT, {
detail: { consented },
detail: { granted },
})
window.dispatchEvent(event)
}
@ -33,14 +33,14 @@ export function dispatchConsentEvent(consented: boolean): void {
/**
* Listen for consent changes
*/
export function onConsentChange(callback: (consented: boolean) => void): () => void {
export function onConsentChange(callback: (granted: boolean) => void): () => void {
if (typeof window === "undefined") {
return () => {}
}
const handler = (event: Event) => {
const customEvent = event as CustomEvent<{ consented: boolean }>
callback(customEvent.detail.consented)
const customEvent = event as CustomEvent<{ granted: boolean }>
callback(customEvent.detail.granted)
}
window.addEventListener(CONSENT_EVENT, handler)