diff --git a/packages/playground/website/src/components/site-error-modal/site-error-modal.tsx b/packages/playground/website/src/components/site-error-modal/site-error-modal.tsx index 1e0a23e77e..412e09a388 100644 --- a/packages/playground/website/src/components/site-error-modal/site-error-modal.tsx +++ b/packages/playground/website/src/components/site-error-modal/site-error-modal.tsx @@ -20,6 +20,7 @@ import type { } from './types'; import { getSiteErrorView } from './get-site-error-view'; import type { SiteInfo } from '../../lib/state/redux/slice-sites'; +import { useKapaAI } from './use-kapa-ai'; export function SiteErrorModal({ error, @@ -38,6 +39,7 @@ export function SiteErrorModal({ isSubmittingReport, handleSubmitReport, } = useErrorReporting(site); + const { isConfigured: isKapaAIConfigured, openWithQuery } = useKapaAI(); const helpers: PresentationHelpers = { deleteSite: () => { @@ -142,8 +144,16 @@ export function SiteErrorModal({

)} - {view.actions.length || !view.isDeveloperError ? ( + {view.actions.length || !view.isDeveloperError || detailText ? (
+ {isKapaAIConfigured && !isReporting && detailText && ( + + )} {!view.isDeveloperError && !isReporting && !reportSubmitted ? ( diff --git a/packages/playground/website/src/components/site-error-modal/use-kapa-ai.ts b/packages/playground/website/src/components/site-error-modal/use-kapa-ai.ts new file mode 100644 index 0000000000..3f9dc9b19f --- /dev/null +++ b/packages/playground/website/src/components/site-error-modal/use-kapa-ai.ts @@ -0,0 +1,97 @@ +import { useEffect, useCallback, useState } from 'react'; +// @ts-ignore - Virtual module injected by Vite +import { kapaWebsiteId } from 'virtual:kapa-ai-config'; + +declare global { + interface Window { + Kapa?: { + open: (options?: { + mode?: 'ai' | 'search'; + query?: string; + submit?: boolean; + }) => void; + close: () => void; + render: (options?: { onRender?: () => void }) => void; + unmount: () => void; + }; + } +} + +const KAPA_SCRIPT_ID = 'kapa-widget-script'; + +export function useKapaAI() { + const [isLoaded, setIsLoaded] = useState(false); + const isConfigured = Boolean(kapaWebsiteId); + + useEffect(() => { + if (!isConfigured) { + return; + } + + // Check if script already exists + if (document.getElementById(KAPA_SCRIPT_ID)) { + if (window.Kapa) { + setIsLoaded(true); + } + return; + } + + const script = document.createElement('script'); + script.id = KAPA_SCRIPT_ID; + script.src = 'https://widget.kapa.ai/kapa-widget.bundle.js'; + script.async = true; + script.setAttribute('data-website-id', kapaWebsiteId); + script.setAttribute('data-project-name', 'WordPress Playground'); + script.setAttribute('data-project-color', '#3858e9'); + script.setAttribute( + 'data-project-logo', + 'https://playground.wordpress.net/logo-square.png' + ); + script.setAttribute('data-button-hide', 'true'); + + script.onload = () => { + const checkKapa = setInterval(() => { + if (window.Kapa) { + clearInterval(checkKapa); + setIsLoaded(true); + } + }, 100); + + setTimeout(() => clearInterval(checkKapa), 5000); + }; + + document.body.appendChild(script); + }, [isConfigured]); + + const openWithQuery = useCallback((query: string) => { + if (window.Kapa) { + window.Kapa.open({ + mode: 'ai', + query: `Suggest a solution or troubleshooting steps for the following error: ${query}`, + submit: true, + }); + + // Move widget container inside screen overlay so it appears on top + const moveContainer = () => { + const container = document.getElementById( + 'kapa-widget-container' + ); + const overlay = document.querySelector( + '.components-modal__screen-overlay' + ); + if (container && overlay) { + overlay.insertBefore(container, overlay.firstChild); + } else { + setTimeout(moveContainer, 50); + } + }; + setTimeout(moveContainer, 50); + } + }, []); + + return { + isConfigured, + isLoaded, + openWithQuery, + }; +} diff --git a/packages/playground/website/vite.config.ts b/packages/playground/website/vite.config.ts index 141daa83c8..3594143c60 100644 --- a/packages/playground/website/vite.config.ts +++ b/packages/playground/website/vite.config.ts @@ -105,6 +105,13 @@ export default defineConfig(({ command, mode }) => { content: ` export const corsProxyUrl = ${JSON.stringify(corsProxyUrl || undefined)};`, }), + virtualModule({ + name: 'kapa-ai-config', + content: ` + export const kapaWebsiteId = ${JSON.stringify( + process.env.KAPA_WEBSITE_ID || '' + )};`, + }), // GitHub OAuth flow { name: 'configure-server',