UNPKG

@sleekio/sdk

Version:

Modern A/B Testing SDK for JavaScript Applications - Production-ready with graceful fallbacks

542 lines (468 loc) โ€ข 13.5 kB
/** * React Examples for Sleek SDK * Comprehensive examples showing different use cases */ import React, { useState, useEffect } from 'react'; import { createAnonymousSleek } from '../src/index.js'; import { SleekProvider, useSleekExperiment, useFeatureFlag, useSleekExperiments, useAdvancedExperiment, useSleekDebug } from '../src/react.js'; // Initialize SDK const sleekSDK = createAnonymousSleek('http://localhost:3001', { batchEvents: true, batchSize: 5, flushInterval: 3000 }); // App wrapper with provider export function SleekDemoApp() { return ( <SleekProvider sdk={sleekSDK}> <div className="demo-app"> <h1>๐Ÿงช Sleek SDK React Examples</h1> <div className="examples-grid"> <BasicExperimentExample /> <FeatureFlagExample /> <MultipleExperimentsExample /> <AdvancedExperimentExample /> <UserAuthenticationExample /> <ConversionTrackingExample /> <PerformanceExample /> {process.env.NODE_ENV === 'development' && <DebugExample />} </div> </div> </SleekProvider> ); } // Basic A/B test example function BasicExperimentExample() { const { variant, config, loading, track } = useSleekExperiment('homepage_cta_test'); const handleClick = () => { track('cta_click', { position: 'example', timestamp: Date.now() }); }; if (loading) { return <div className="loading">Loading experiment...</div>; } return ( <div className="example-card"> <h3>Basic A/B Test</h3> <p>Variant: <strong>{variant}</strong></p> <button onClick={handleClick} style={{ backgroundColor: config.buttonColor || '#3B82F6', color: 'white', padding: '12px 24px', border: 'none', borderRadius: '6px', fontSize: config.buttonSize === 'large' ? '18px' : '16px', cursor: 'pointer' }} > {config.buttonText || 'Default Button'} </button> <div className="variant-info"> <small>Config: {JSON.stringify(config, null, 2)}</small> </div> </div> ); } // Feature flag example function FeatureFlagExample() { const { variant, loading } = useFeatureFlag('new_dashboard_enabled'); if (loading) return <div>Loading feature...</div>; return ( <div className="example-card"> <h3>Feature Flag</h3> {variant === 'enabled' ? ( <div className="new-feature"> <h4>๐Ÿ†• New Dashboard</h4> <p>You're seeing the new dashboard design!</p> <div style={{ background: 'linear-gradient(45deg, #667eea 0%, #764ba2 100%)', padding: '20px', borderRadius: '8px', color: 'white' }}> <p>โœจ Enhanced Analytics</p> <p>๐Ÿ“Š Real-time Data</p> <p>๐ŸŽจ Modern UI</p> </div> </div> ) : ( <div className="old-feature"> <h4>๐Ÿ“Š Standard Dashboard</h4> <p>You're seeing the standard dashboard.</p> <div style={{ background: '#f3f4f6', padding: '20px', borderRadius: '8px' }}> <p>๐Ÿ“ˆ Basic Analytics</p> <p>๐Ÿ“‹ Standard Reports</p> </div> </div> )} <p>Feature status: <strong>{variant}</strong></p> </div> ); } // Multiple experiments example function MultipleExperimentsExample() { const experimentIds = [ 'homepage_cta_test', 'checkout_flow_optimization', 'pricing_page_layout' ]; const { experiments, loading, errors, track } = useSleekExperiments(experimentIds); const handleExperimentInteraction = (experimentId, action) => { track(experimentId, action, { source: 'multiple_experiments_example', timestamp: Date.now() }); }; if (loading) { return <div className="loading">Loading experiments...</div>; } return ( <div className="example-card"> <h3>Multiple Experiments</h3> {Object.entries(experiments).map(([experimentId, data]) => ( <div key={experimentId} className="experiment-row"> <strong>{experimentId}:</strong> {data.variant} <button onClick={() => handleExperimentInteraction(experimentId, 'interaction')} style={{ marginLeft: '10px', padding: '4px 8px' }} > Track </button> {errors[experimentId] && ( <div className="error">Error: {errors[experimentId]}</div> )} </div> ))} </div> ); } // Advanced experiment with auto-tracking function AdvancedExperimentExample() { const { variant, config, loading, track, trackConversion, isVariant, getVariantValue } = useAdvancedExperiment('checkout_flow_optimization', { autoTrackPageView: true, autoTrackMount: true, componentName: 'AdvancedExperimentExample' }); const [step, setStep] = useState(1); const handleNextStep = () => { track('step_progression', { from: step, to: step + 1, layout: variant }); setStep(s => s + 1); }; const handleComplete = () => { trackConversion({ steps_completed: step, layout: variant, completion_time: Date.now() }); setStep(1); // Reset }; if (loading) return <div>Loading advanced experiment...</div>; return ( <div className="example-card"> <h3>Advanced Experiment</h3> <p>Layout: <strong>{variant}</strong></p> {isVariant('multi_step') ? ( <div className="multi-step-flow"> <div className="progress-bar"> {getVariantValue('showProgressBar', false) && ( <div style={{ width: '100%', background: '#e5e7eb', borderRadius: '4px', marginBottom: '16px' }}> <div style={{ width: `${(step / 4) * 100}%`, background: '#3b82f6', height: '8px', borderRadius: '4px', transition: 'width 0.3s ease' }} /> </div> )} </div> <div className="step-content"> <h4>Step {step} of 4</h4> <p>Current step: {getVariantValue('steps', [])[step - 1] || 'unknown'}</p> {step < 4 ? ( <button onClick={handleNextStep}>Next Step</button> ) : ( <button onClick={handleComplete} style={{ background: '#10b981' }}> Complete </button> )} </div> </div> ) : ( <div className="single-page-flow"> <h4>Single Page Checkout</h4> <p>All information on one page</p> <button onClick={handleComplete}>Complete Checkout</button> </div> )} </div> ); } // User authentication flow example function UserAuthenticationExample() { const [isAuthenticated, setIsAuthenticated] = useState(false); const [userEmail, setUserEmail] = useState(''); const handleLogin = () => { const email = prompt('Enter email:'); if (email) { sleekSDK.setUser(`user_${Date.now()}`, { email, loginMethod: 'demo', loginTime: new Date().toISOString() }); setUserEmail(email); setIsAuthenticated(true); } }; const handleLogout = () => { sleekSDK.clearUser(); setUserEmail(''); setIsAuthenticated(false); }; const userContext = sleekSDK.getUserContext(); return ( <div className="example-card"> <h3>User Authentication</h3> <div className="auth-status"> <p>Status: <strong>{isAuthenticated ? 'Authenticated' : 'Anonymous'}</strong></p> <p>User ID: <code>{sleekSDK.getUserId()}</code></p> {isAuthenticated && <p>Email: {userEmail}</p>} </div> <div className="auth-actions"> {!isAuthenticated ? ( <button onClick={handleLogin}>Login (Demo)</button> ) : ( <button onClick={handleLogout}>Logout</button> )} </div> <details> <summary>User Context</summary> <pre>{JSON.stringify(userContext, null, 2)}</pre> </details> </div> ); } // Conversion tracking example function ConversionTrackingExample() { const { variant, track, trackConversion } = useSleekExperiment('homepage_cta_test'); const [conversionCount, setConversionCount] = useState(0); const handleAddToCart = () => { track('add_to_cart', { product: 'demo_product', variant, price: 29.99 }); }; const handlePurchase = () => { trackConversion({ value: 29.99, currency: 'USD', product: 'demo_product', conversion_type: 'purchase' }); setConversionCount(c => c + 1); }; return ( <div className="example-card"> <h3>Conversion Tracking</h3> <p>Variant: <strong>{variant}</strong></p> <p>Conversions: <strong>{conversionCount}</strong></p> <div className="conversion-actions"> <button onClick={handleAddToCart} style={{ marginRight: '10px' }}> Add to Cart </button> <button onClick={handlePurchase} style={{ background: '#10b981', color: 'white' }} > Purchase ($29.99) </button> </div> </div> ); } // Performance monitoring example function PerformanceExample() { const [performanceData, setPerformanceData] = useState({}); useEffect(() => { const startTime = performance.now(); // Simulate some work setTimeout(() => { const loadTime = performance.now() - startTime; setPerformanceData({ loadTime: Math.round(loadTime), timestamp: new Date().toLocaleTimeString() }); // Track performance sleekSDK.track('performance_example', 'component_load', { loadTime: Math.round(loadTime), component: 'PerformanceExample' }); }, Math.random() * 500 + 100); // Random delay 100-600ms }, []); return ( <div className="example-card"> <h3>Performance Monitoring</h3> {performanceData.loadTime ? ( <div> <p>Load Time: <strong>{performanceData.loadTime}ms</strong></p> <p>Measured At: {performanceData.timestamp}</p> <p>Performance: { performanceData.loadTime < 200 ? '๐ŸŸข Fast' : performanceData.loadTime < 500 ? '๐ŸŸก Moderate' : '๐Ÿ”ด Slow' }</p> </div> ) : ( <div>โฑ๏ธ Measuring performance...</div> )} </div> ); } // Debug panel (development only) function DebugExample() { const { debugInfo, logDebugInfo, forceReassign } = useSleekDebug('homepage_cta_test'); const [showDetails, setShowDetails] = useState(false); return ( <div className="example-card debug-panel"> <h3>๐Ÿ› Debug Panel</h3> <p><small>Development only</small></p> <div className="debug-actions"> <button onClick={logDebugInfo}>Log Debug Info</button> <button onClick={forceReassign} style={{ marginLeft: '10px' }}> Force Reassign </button> <button onClick={() => setShowDetails(!showDetails)} style={{ marginLeft: '10px' }} > {showDetails ? 'Hide' : 'Show'} Details </button> </div> {showDetails && ( <details open> <summary>Debug Information</summary> <pre style={{ fontSize: '12px', overflow: 'auto' }}> {JSON.stringify(debugInfo, null, 2)} </pre> </details> )} </div> ); } // CSS styles (would typically be in a separate file) const styles = ` .demo-app { font-family: system-ui, -apple-system, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; } .examples-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 20px; margin-top: 20px; } .example-card { border: 1px solid #e5e7eb; border-radius: 8px; padding: 20px; background: white; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .example-card h3 { margin-top: 0; color: #1f2937; } .loading { color: #6b7280; font-style: italic; } .error { color: #ef4444; font-size: 12px; margin-top: 4px; } .experiment-row { padding: 8px 0; border-bottom: 1px solid #f3f4f6; } .experiment-row:last-child { border-bottom: none; } .auth-status { background: #f9fafb; padding: 12px; border-radius: 6px; margin: 10px 0; } .auth-status code { background: #e5e7eb; padding: 2px 4px; border-radius: 3px; font-size: 12px; } .debug-panel { border-color: #f59e0b; background: #fffbeb; } button { background: #3b82f6; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-size: 14px; } button:hover { background: #2563eb; } .variant-info { margin-top: 10px; padding: 8px; background: #f3f4f6; border-radius: 4px; font-family: monospace; font-size: 12px; } `; // Inject styles if (typeof document !== 'undefined') { const styleSheet = document.createElement('style'); styleSheet.textContent = styles; document.head.appendChild(styleSheet); } export default SleekDemoApp;