@sleekio/sdk
Version:
Modern A/B Testing SDK for JavaScript Applications - Production-ready with graceful fallbacks
542 lines (468 loc) โข 13.5 kB
JSX
/**
* 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;