UNPKG

admesh-ui-sdk

Version:

Beautiful, modern React components for displaying AI-powered product recommendations with citation-based conversation ads, auto-triggered widgets, floating chat, conversational interfaces, persistent sidebar, and built-in tracking

247 lines (225 loc) 7.41 kB
// Next.js Integration Example - AdMesh UI SDK import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { AdMeshLayout } from '@admesh/ui-sdk'; import '@admesh/ui-sdk/dist/ui-sdk.css'; // Example API function to fetch recommendations async function fetchRecommendations(query, userId) { try { const response = await fetch('/api/recommendations', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query, user_id: userId, format: 'auto' }) }); if (!response.ok) { throw new Error('Failed to fetch recommendations'); } const data = await response.json(); return data.recommendations || []; } catch (error) { console.error('Error fetching recommendations:', error); return []; } } // Main recommendations page component export default function RecommendationsPage({ initialRecommendations, query }) { const router = useRouter(); const [recommendations, setRecommendations] = useState(initialRecommendations || []); const [loading, setLoading] = useState(false); const [darkMode, setDarkMode] = useState(false); // Handle dark mode toggle useEffect(() => { const isDark = localStorage.getItem('darkMode') === 'true' || window.matchMedia('(prefers-color-scheme: dark)').matches; setDarkMode(isDark); }, []); const toggleDarkMode = () => { const newMode = !darkMode; setDarkMode(newMode); localStorage.setItem('darkMode', newMode.toString()); }; // Handle product clicks with analytics const handleProductClick = (adId, admeshLink) => { // Google Analytics tracking if (typeof gtag !== 'undefined') { gtag('event', 'recommendation_click', { event_category: 'AdMesh', event_label: adId, custom_map: { 'custom_parameter_1': query } }); } // Custom analytics tracking if (window.analytics) { window.analytics.track('Recommendation Clicked', { ad_id: adId, query: query, page: router.pathname, timestamp: new Date().toISOString() }); } // Open the tracked link window.open(admeshLink, '_blank'); }; // Handle product views const handleProductView = (adId, productId) => { if (typeof gtag !== 'undefined') { gtag('event', 'recommendation_view', { event_category: 'AdMesh', event_label: adId }); } }; // Refresh recommendations const refreshRecommendations = async () => { setLoading(true); try { const newRecommendations = await fetchRecommendations(query, 'user-123'); setRecommendations(newRecommendations); } catch (error) { console.error('Failed to refresh recommendations:', error); } finally { setLoading(false); } }; return ( <div className={`min-h-screen transition-colors duration-300 ${ darkMode ? 'bg-gray-900' : 'bg-gray-50' }`}> {/* Header */} <header className={`border-b transition-colors duration-300 ${ darkMode ? 'bg-gray-800 border-gray-700' : 'bg-white border-gray-200' }`}> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="flex justify-between items-center h-16"> <div> <h1 className={`text-xl font-semibold ${ darkMode ? 'text-white' : 'text-gray-900' }`}> Product Recommendations </h1> {query && ( <p className={`text-sm ${ darkMode ? 'text-gray-400' : 'text-gray-600' }`}> Results for "{query}" </p> )} </div> <div className="flex items-center gap-4"> {/* Refresh button */} <button onClick={refreshRecommendations} disabled={loading} className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${ darkMode ? 'bg-gray-700 text-white hover:bg-gray-600 disabled:bg-gray-800' : 'bg-gray-100 text-gray-900 hover:bg-gray-200 disabled:bg-gray-50' } disabled:opacity-50 disabled:cursor-not-allowed`} > {loading ? 'Refreshing...' : 'Refresh'} </button> {/* Dark mode toggle */} <button onClick={toggleDarkMode} className={`p-2 rounded-lg transition-colors ${ darkMode ? 'bg-gray-700 text-yellow-400 hover:bg-gray-600' : 'bg-gray-100 text-gray-600 hover:bg-gray-200' }`} aria-label="Toggle dark mode" > {darkMode ? '☀️' : '🌙'} </button> </div> </div> </div> </header> {/* Main content */} <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> {loading ? ( <div className="flex justify-center items-center h-64"> <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-indigo-600"></div> </div> ) : recommendations.length > 0 ? ( <AdMeshLayout recommendations={recommendations} intentType="best_for_use_case" theme={{ mode: darkMode ? "dark" : "light", accentColor: "#6366f1" }} maxDisplayed={9} showMatchScores={true} showFeatures={true} autoLayout={true} onProductClick={handleProductClick} onTrackView={handleProductView} /> ) : ( <div className={`text-center py-12 ${ darkMode ? 'text-gray-400' : 'text-gray-600' }`}> <p className="text-lg mb-4">No recommendations found</p> <button onClick={refreshRecommendations} className="px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors" > Try Again </button> </div> )} </main> </div> ); } // Server-side rendering with getServerSideProps export async function getServerSideProps(context) { const { query } = context.query; try { // Fetch initial recommendations on the server const initialRecommendations = await fetchRecommendations( query || 'productivity tools', context.req.headers['x-user-id'] || 'anonymous' ); return { props: { initialRecommendations, query: query || null } }; } catch (error) { console.error('Error in getServerSideProps:', error); return { props: { initialRecommendations: [], query: query || null } }; } } // Alternative: Static generation with getStaticProps export async function getStaticProps() { try { const recommendations = await fetchRecommendations('popular tools', 'default'); return { props: { initialRecommendations: recommendations }, revalidate: 3600 // Revalidate every hour }; } catch (error) { return { props: { initialRecommendations: [] } }; } }