diff --git a/app/src/components/composio/ComposioConnectModal.tsx b/app/src/components/composio/ComposioConnectModal.tsx index 846c5072b..8ae03d4bd 100644 --- a/app/src/components/composio/ComposioConnectModal.tsx +++ b/app/src/components/composio/ComposioConnectModal.tsx @@ -13,7 +13,7 @@ * keep the Skills page badge in sync too, so the card reflects the new * state as soon as the modal closes. */ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { type ChangeEvent, useCallback, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { @@ -73,6 +73,9 @@ export default function ComposioConnectModal({ ); const [error, setError] = useState(null); const [connectUrl, setConnectUrl] = useState(null); + // WhatsApp Business requires a WABA ID before the OAuth flow can start. + const [wabaId, setWabaId] = useState(''); + const needsWabaId = toolkit.slug === 'whatsapp'; const [activeConnection, setActiveConnection] = useState( connection ); @@ -188,11 +191,16 @@ export default function ComposioConnectModal({ }, []); const handleConnect = useCallback(async () => { + if (needsWabaId && !wabaId.trim()) { + setError('Please enter your WhatsApp Business Account ID (WABA ID) to continue.'); + return; + } setPhase('authorizing'); setError(null); setConnectUrl(null); try { - const resp = await authorize(toolkit.slug); + const extraParams = needsWabaId ? { waba_id: wabaId.trim() } : undefined; + const resp = await authorize(toolkit.slug, extraParams); setConnectUrl(resp.connectUrl); await openUrl(resp.connectUrl); setPhase('waiting'); @@ -202,7 +210,7 @@ export default function ComposioConnectModal({ setPhase('error'); setError(`Authorization failed: ${msg}`); } - }, [startPolling, toolkit.slug]); + }, [needsWabaId, startPolling, toolkit.slug, wabaId]); // Fetch the stored scope pref whenever the modal lands in the // 'connected' phase. Re-fetching each time we transition (rather @@ -360,6 +368,35 @@ export default function ComposioConnectModal({ admin toggles.

+ {needsWabaId && ( +
+ + ) => { + setWabaId(e.target.value); + if (error) setError(null); + }} + placeholder="e.g. 123456789012345" + className="w-full rounded-xl border border-stone-200 bg-white px-3 py-2 text-sm text-stone-900 placeholder:text-stone-400 focus:border-primary-400 focus:outline-none focus:ring-2 focus:ring-primary-100" + /> +

+ Find it via GET /me/businesses then{' '} + + GET /{business_id}/owned_whatsapp_business_accounts + {' '} + using your Meta access token. +

+
+ )} + {error && phase === 'idle' &&

{error}

}