UNPKG

@konvo-ai/sdk-web

Version:

KonvoAI Conversational Ad SDK for Web Applications - Intelligent contextual advertising with AI-powered decision engine

127 lines (126 loc) 4.58 kB
import React, { useEffect, useState } from 'react'; import { KonvoAIAds } from '../core'; export const KonvoAIAdsView = ({ surface, user, chat, className = '', onLoad, onError }) => { const [ad, setAd] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const loadAd = async () => { try { const response = await KonvoAIAds.decide({ user, chat, surface }); if (response.fill) { setAd(response); await KonvoAIAds.handleImpression(response); onLoad?.(); } else { setAd(null); onLoad?.(); } } catch (error) { console.error('Failed to load ad:', error); onError?.(error); setAd(null); } finally { setLoading(false); } }; loadAd(); }, [surface, user.anonId, chat.lastUserMsg]); if (loading) { return React.createElement("div", { className: `konvo-ai-ads-loading ${className}` }, "Loading..."); } if (!ad || !ad.fill || !ad.render) { return null; } const baseStyles = { padding: '12px', borderRadius: '8px', backgroundColor: '#f8f9fa', border: '1px solid #e0e0e0', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' }; const surfaceStyles = { 'inline-chip': { ...baseStyles, display: 'inline-flex', alignItems: 'center', gap: '12px', maxWidth: '400px' }, 'banner': { ...baseStyles, display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }, 'interstitial': { ...baseStyles, position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', zIndex: 1000, minWidth: '300px', maxWidth: '500px', boxShadow: '0 4px 12px rgba(0,0,0,0.15)' }, 'native': { ...baseStyles, display: 'flex', flexDirection: 'column', gap: '8px' } }; return (React.createElement("div", { className: `konvo-ai-ads-view konvo-ai-ads-${surface} ${className}`, style: surfaceStyles[surface] }, ad.render.imageUrl && (React.createElement("img", { src: ad.render.imageUrl, alt: "", style: { width: surface === 'inline-chip' ? '40px' : '80px', height: surface === 'inline-chip' ? '40px' : '80px', borderRadius: '4px', objectFit: 'cover' } })), React.createElement("div", { style: { flex: 1 } }, React.createElement("h4", { style: { margin: '0 0 4px 0', fontSize: '14px', fontWeight: '600', color: '#333' } }, ad.render.title), React.createElement("p", { style: { margin: '0 0 8px 0', fontSize: '13px', color: '#666', lineHeight: '1.4' } }, ad.render.desc), React.createElement("button", { onClick: ad.render.cta.handler, style: { padding: '6px 12px', backgroundColor: '#0066cc', color: 'white', border: 'none', borderRadius: '4px', fontSize: '13px', fontWeight: '500', cursor: 'pointer', transition: 'background-color 0.2s' }, onMouseEnter: (e) => { e.currentTarget.style.backgroundColor = '#0052a3'; }, onMouseLeave: (e) => { e.currentTarget.style.backgroundColor = '#0066cc'; } }, ad.render.cta.label)), React.createElement("span", { style: { position: 'absolute', top: '4px', right: '4px', fontSize: '10px', color: '#999', backgroundColor: 'rgba(255,255,255,0.9)', padding: '2px 4px', borderRadius: '2px' } }, "Ad"))); };