1- import { useKapaConfig } from "~/root" ;
21import { useShortcuts } from "../components/primitives/ShortcutsProvider" ;
32import { useFeatures } from "~/hooks/useFeatures" ;
43import { useCallback , useEffect , useState } from "react" ;
4+ import { useMatches } from "@remix-run/react" ;
5+ import { useTypedMatchesData } from "./useTypedMatchData" ;
6+ import { type loader } from "~/root" ;
7+
8+ type OpenOptions = { mode : string ; query : string ; submit : boolean } ;
59
610declare global {
711 interface Window {
8- Kapa : ( (
12+ Kapa : (
913 command : string ,
10- options ?: ( ) => void ,
14+ options ?: ( ( ) => void ) | OpenOptions ,
1115 remove ?: string | { onRender ?: ( ) => void }
12- ) => void ) & {
13- open : ( options ?: { mode : string ; query : string ; submit : boolean } ) => void ;
14- } ;
16+ ) => void ;
1517 }
1618}
1719
20+ export function KapaScripts ( { websiteId } : { websiteId ?: string } ) {
21+ if ( ! websiteId ) return null ;
22+
23+ return (
24+ < >
25+ < script
26+ async
27+ src = "https://widget.kapa.ai/kapa-widget.bundle.js"
28+ data-website-id = { websiteId }
29+ data-project-name = { "Trigger.dev" }
30+ data-project-color = { "#C7D2FE" }
31+ data-project-logo = { "https://content.trigger.dev/trigger-logo-circle.png" }
32+ data-render-on-load = { "false" }
33+ data-button-hide = { "true" }
34+ data-modal-disclaimer-bg-color = { "#1A1B1F" }
35+ data-modal-disclaimer-text-color = { "#878C99" }
36+ data-modal-header-bg-color = { "#2C3034" }
37+ data-modal-body-bg-color = { "#4D525B" }
38+ data-query-input-text-color = { "#15171A" }
39+ data-query-input-placeholder-text-color = { "#878C99" }
40+ data-modal-title-color = { "#D7D9DD" }
41+ data-button-text-color = { "#D7D9DD" }
42+ > </ script >
43+ < script
44+ dangerouslySetInnerHTML = { {
45+ __html : `
46+ (function () {
47+ let k = window.Kapa;
48+ if (!k) {
49+ let i = function () {
50+ i.c(arguments);
51+ };
52+ i.q = [];
53+ i.c = function (args) {
54+ i.q.push(args);
55+ };
56+ window.Kapa = i;
57+ }
58+ })();
59+ ` ,
60+ } }
61+ />
62+ </ >
63+ ) ;
64+ }
65+
66+ export function useKapaConfig ( ) {
67+ const matches = useMatches ( ) ;
68+ const routeMatch = useTypedMatchesData < typeof loader > ( {
69+ id : "root" ,
70+ matches,
71+ } ) ;
72+ return routeMatch ?. kapa ;
73+ }
74+
1875export function useKapaWidget ( ) {
1976 const kapa = useKapaConfig ( ) ;
2077 const features = useFeatures ( ) ;
2178 const { disableShortcuts, enableShortcuts, areShortcutsEnabled } = useShortcuts ( ) ;
2279 const [ isKapaOpen , setIsKapaOpen ] = useState ( false ) ;
2380
24- useEffect ( ( ) => {
25- if ( ! features . isManagedCloud || ! kapa ?. websiteId ) return ;
26-
27- loadScriptIfNotExists ( kapa . websiteId ) ;
28-
29- // Define the handler function
30- const handleModalClose = ( ) => {
31- setIsKapaOpen ( false ) ;
32- enableShortcuts ( ) ;
33- } ;
81+ const handleModalClose = useCallback ( ( ) => {
82+ setIsKapaOpen ( false ) ;
83+ enableShortcuts ( ) ;
84+ } , [ enableShortcuts ] ) ;
3485
35- const handleModalOpen = ( ) => {
36- setIsKapaOpen ( true ) ;
37- disableShortcuts ( ) ;
38- } ;
86+ const handleModalOpen = useCallback ( ( ) => {
87+ setIsKapaOpen ( true ) ;
88+ disableShortcuts ( ) ;
89+ } , [ disableShortcuts ] ) ;
3990
40- const kapaInterval = setInterval ( ( ) => {
41- if ( typeof window . Kapa === "function" ) {
42- clearInterval ( kapaInterval ) ;
43- window . Kapa ( "render" ) ;
44- window . Kapa ( "onModalClose" , handleModalClose ) ;
91+ useEffect ( ( ) => {
92+ if ( ! features . isManagedCloud || ! kapa ?. websiteId ) return ;
4593
46- // Register onModalOpen handler
47- window . Kapa ( "onModalOpen" , handleModalOpen ) ;
48- }
49- } , 100 ) ;
94+ window . Kapa ( "render" ) ;
95+ window . Kapa ( "onModalOpen" , handleModalOpen ) ;
96+ window . Kapa ( "onModalClose" , handleModalClose ) ;
5097
51- // Clear interval on unmount to prevent memory leaks
5298 return ( ) => {
53- clearInterval ( kapaInterval ) ;
54- if ( typeof window . Kapa === "function" ) {
55- window . Kapa ( "unmount" ) ;
56-
57- window . Kapa ( "onModalOpen" , handleModalOpen , "remove" ) ;
58- window . Kapa ( "onModalClose" , handleModalClose , "remove" ) ;
59- }
99+ window . Kapa ( "onModalOpen" , handleModalOpen , "remove" ) ;
100+ window . Kapa ( "onModalClose" , handleModalClose , "remove" ) ;
60101 } ;
61- } , [ features . isManagedCloud , kapa ?. websiteId , disableShortcuts , enableShortcuts ] ) ;
102+ } , [ features . isManagedCloud , kapa ?. websiteId ] ) ;
62103
63104 const openKapa = useCallback (
64105 ( query ?: string ) => {
65106 if ( ! features . isManagedCloud || ! kapa ?. websiteId ) return ;
66107
67- if ( typeof window . Kapa === "function" ) {
68- window . Kapa . open (
69- query
70- ? {
71- mode : "ai" ,
72- query,
73- submit : true ,
74- }
75- : undefined
76- ) ;
77- setIsKapaOpen ( true ) ;
78- disableShortcuts ( ) ;
79- }
108+ window . Kapa (
109+ "open" ,
110+ query
111+ ? {
112+ mode : "ai" ,
113+ query,
114+ submit : true ,
115+ }
116+ : undefined
117+ ) ;
118+ setIsKapaOpen ( true ) ;
119+ disableShortcuts ( ) ;
80120 } ,
81121 [ disableShortcuts , features . isManagedCloud , kapa ?. websiteId ]
82122 ) ;
@@ -87,38 +127,3 @@ export function useKapaWidget() {
87127 isKapaOpen,
88128 } ;
89129}
90-
91- function loadScriptIfNotExists ( websiteId : string ) {
92- const scriptSrc = "https://widget.kapa.ai/kapa-widget.bundle.js" ;
93-
94- if ( document . querySelector ( `script[src="${ scriptSrc } "]` ) ) {
95- return ;
96- }
97-
98- const script = document . createElement ( "script" ) ;
99- script . async = true ;
100- script . src = scriptSrc ;
101-
102- const attributes = {
103- "data-website-id" : websiteId ,
104- "data-project-name" : "Trigger.dev" ,
105- "data-project-color" : "#C7D2FE" ,
106- "data-project-logo" : "https://content.trigger.dev/trigger-logo-circle.png" ,
107- "data-render-on-load" : "false" ,
108- "data-button-hide" : "true" ,
109- "data-modal-disclaimer-bg-color" : "#1A1B1F" ,
110- "data-modal-disclaimer-text-color" : "#878C99" ,
111- "data-modal-header-bg-color" : "#2C3034" ,
112- "data-modal-body-bg-color" : "#4D525B" ,
113- "data-query-input-text-color" : "#15171A" ,
114- "data-query-input-placeholder-text-color" : "#878C99" ,
115- "data-modal-title-color" : "#D7D9DD" ,
116- "data-button-text-color" : "#D7D9DD" ,
117- } ;
118-
119- Object . entries ( attributes ) . forEach ( ( [ key , value ] ) => {
120- script . setAttribute ( key , value ) ;
121- } ) ;
122-
123- document . head . appendChild ( script ) ;
124- }
0 commit comments