113 lines
3.6 KiB
TypeScript
Executable file
113 lines
3.6 KiB
TypeScript
Executable file
import React, { useState } from 'react'
|
|
|
|
import {
|
|
useABTestMetrics,
|
|
useActiveTests,
|
|
} from '../hooks/useAdminQuery'
|
|
|
|
export const ABTestingPage: React.FC = () => {
|
|
const { data: metrics, isLoading, isError } = useABTestMetrics()
|
|
const { data: activeTests } = useActiveTests()
|
|
const [filter, setFilter] = useState<'all' | 'running' | 'completed'>('all')
|
|
|
|
if (isLoading) {
|
|
return <div>Loading a/b test data...</div>
|
|
}
|
|
|
|
if (isError) {
|
|
return <div>Failed to load A/B test data</div>
|
|
}
|
|
|
|
const filteredTests = activeTests?.filter((test) => {
|
|
if (filter === 'all') return true
|
|
return test.status === filter
|
|
})
|
|
|
|
return (
|
|
<div className="ab-testing-page">
|
|
<h1 data-testid="page-title">A/B Testing Analytics</h1>
|
|
|
|
{/* KPI Cards */}
|
|
<div className="kpi-cards">
|
|
<div className="kpi-card">
|
|
<div className="kpi-label">Active Tests</div>
|
|
<div className="kpi-value">{metrics?.activeTests}</div>
|
|
</div>
|
|
<div className="kpi-card">
|
|
<div className="kpi-label">Completed Tests</div>
|
|
<div className="kpi-value">{metrics?.completedTests}</div>
|
|
</div>
|
|
<div className="kpi-card">
|
|
<div className="kpi-label">Significant Results</div>
|
|
<div className="kpi-value">{metrics?.significantResults}</div>
|
|
</div>
|
|
<div className="kpi-card">
|
|
<div className="kpi-label">Avg Lift</div>
|
|
<div className="kpi-value">{metrics?.avgLiftPercent}%</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Filter Buttons */}
|
|
<div className="filters">
|
|
<button onClick={() => setFilter('all')}>All</button>
|
|
<button onClick={() => setFilter('running')}>Running</button>
|
|
<button onClick={() => setFilter('completed')}>Completed</button>
|
|
</div>
|
|
|
|
{/* Create Test Button */}
|
|
<button className="create-test-btn">Create New Test</button>
|
|
|
|
{/* Active Tests Table */}
|
|
<div className="active-tests-section">
|
|
<h2>Active A/B Tests</h2>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Name</th>
|
|
<th>Status</th>
|
|
<th>Variants</th>
|
|
<th>Participants</th>
|
|
<th>Conversion Rate A</th>
|
|
<th>Conversion Rate B</th>
|
|
<th>Significance</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{filteredTests?.map((test) => (
|
|
<tr key={test.id}>
|
|
<td>{test.id}</td>
|
|
<td>{test.name}</td>
|
|
<td>{test.status}</td>
|
|
<td>{test.variants} variants</td>
|
|
<td>{test.participants.toLocaleString()}</td>
|
|
<td>{test.conversionRateA}%</td>
|
|
<td>{test.conversionRateB}%</td>
|
|
<td>{test.significance}%</td>
|
|
<td>
|
|
<button>View Details</button>
|
|
{test.status === 'running' && <button>Stop Test</button>}
|
|
{test.status === 'running' && test.significance > 95 && (
|
|
<button>Declare Winner</button>
|
|
)}
|
|
{test.winner && <div>Winner: {test.winner}</div>}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{/* Test Details */}
|
|
<div className="test-details">
|
|
{activeTests?.map((test) => (
|
|
<div key={test.id}>
|
|
<div>Start Date: {test.startDate}</div>
|
|
{test.endDate && <div>End Date: {test.endDate}</div>}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|