import { __ } from '@wordpress/i18n'; import { useCallback, useEffect, useMemo, useState } from '@wordpress/element'; import { Button } from '@wordpress/components'; import Table from '../shared/Table'; import ABConversionBar from '../shared/ABConversionBar'; import NoDataPlaceholder from '../shared/NoDataPlaceholder'; const getAnalyticsAbTestsAPI = () => { if ( typeof window === 'undefined' ) { return {} as Record< string, any >; } const growthstack = ( window as any ).growthstack ?? {}; return growthstack.analyticsAbTests ?? {}; }; const formatTrendValue = ( value: number, format: string ) => { if ( format === 'compact' ) { if ( value >= 1000000 ) { return `${ ( value / 1000000 ).toFixed( 1 ) }M`; } if ( value >= 1000 ) { return `${ ( value / 1000 ).toFixed( 1 ) }k`; } } return value.toString(); }; const formatString = ( template: string, ...args: any[] ) => { let i = 0; return template.replace( /%s/g, () => args[ i++ ] ); }; const formatDate = ( publishedAt: string ) => { if ( ! publishedAt ) { return __( 'Draft', 'liana-with-growthstack' ); } const date = new Date( publishedAt ); const formattedDate = date.toLocaleDateString( 'fi-FI', { year: 'numeric', month: 'numeric', day: 'numeric', } ); return formatString( __( 'Since %s', 'liana-with-growthstack' ), formattedDate ); }; const getPlaceholderData = () => [ { title: 'Ultimate Guide to Web Performance', type: 'post', days: 14, publishedAt: new Date( Date.now() - 14 * 24 * 60 * 60 * 1000 ).toISOString(), views: 3420, conversionsA: 145, conversionsB: 178, }, { title: 'Getting Started with A/B Testing', type: 'post', days: 7, publishedAt: new Date( Date.now() - 7 * 24 * 60 * 60 * 1000 ).toISOString(), views: 1850, conversionsA: 92, conversionsB: 87, }, { title: 'Product Features Overview', type: 'page', days: 21, publishedAt: new Date( Date.now() - 21 * 24 * 60 * 60 * 1000 ).toISOString(), views: 5230, conversionsA: 234, conversionsB: 289, }, { title: 'Contact Us - Get in Touch', type: 'page', days: 3, publishedAt: new Date( Date.now() - 3 * 24 * 60 * 60 * 1000 ).toISOString(), views: 890, conversionsA: 45, conversionsB: 52, }, { title: 'Best Practices for 2026', type: 'post', days: 10, publishedAt: new Date( Date.now() - 10 * 24 * 60 * 60 * 1000 ).toISOString(), views: 2100, conversionsA: 118, conversionsB: 105, }, { title: 'How to Optimize Your Landing Pages', type: 'page', days: 5, publishedAt: new Date( Date.now() - 5 * 24 * 60 * 60 * 1000 ).toISOString(), views: 1420, conversionsA: 68, conversionsB: 74, }, { title: 'Advanced Marketing Strategies', type: 'post', days: 28, publishedAt: new Date( Date.now() - 28 * 24 * 60 * 60 * 1000 ).toISOString(), views: 4780, conversionsA: 198, conversionsB: 215, }, ]; const DefaultABTestsContent = ( props: { upgradeUrl?: string } ) => { const placeholderData = getPlaceholderData(); return ( <>

{ __( 'A/B Tests', 'liana-with-growthstack' ) }

{ __( 'Active A/B Tests from all posts and pages.', 'liana-with-growthstack' ) }

(
{ row.original.title } { row.original.type }
), }, { Header: __( 'Running', 'liana-with-growthstack' ), accessor: 'days', width: 120, minWidth: 100, maxWidth: 120, Cell: ( { row } ) => (
{ row.original.days === 1 ? formatString( __( '%s day', 'liana-with-growthstack' ), row.original.days ) : formatString( __( '%s days', 'liana-with-growthstack' ), row.original.days ) } { formatDate( row.original.publishedAt ) }
), }, { Header: __( 'Conversion Distribution', 'liana-with-growthstack' ), accessor: 'conversionsA', width: 140, minWidth: 130, maxWidth: 140, Cell: ( { row } ) => ( ), }, { Header: __( 'Views', 'liana-with-growthstack' ), accessor: 'views', width: 90, minWidth: 80, maxWidth: 100, Cell: ( { row } ) => ( { formatTrendValue( row.original.views, 'compact' ) } ), }, { Header: ' ', Cell: ( { row } ) => ( ), }, ] } data={ placeholderData } />

{ __( 'Available for Pro version', 'liana-with-growthstack' ) }

{ __( 'Get Liana with GrowthStack Pro to run experiments and compare results between variants. A/B Testing is a powerful way to optimize your content and boost conversions across your site.', 'liana-with-growthstack' ) }

{ props.upgradeUrl && ( { __( 'Upgrade to Pro', 'liana-with-growthstack' ) } ) }
); }; export default function ABTests( props ) { const { assetsFolder, upgradeUrl } = props; const [ dataCache, setDataCache ] = useState( {} ); const [ registryVersion, setRegistryVersion ] = useState( 0 ); const getCachedData = useCallback( ( endpoint ) => { return dataCache[ endpoint ] || null; }, [ dataCache ] ); const setCachedData = useCallback( ( endpoint, data, error = null ) => { setDataCache( ( prevCache ) => ( { ...prevCache, [ endpoint ]: { data, error, isFetched: true }, } ) ); }, [ setDataCache ] ); useEffect( () => { let unsubscribe: () => void = () => {}; let pollHandle: number | null = null; let isSubscribed = false; const attemptSubscribe = () => { const { subscribeABTestsScreens } = getAnalyticsAbTestsAPI(); if ( typeof subscribeABTestsScreens === 'function' ) { unsubscribe = subscribeABTestsScreens( () => { setRegistryVersion( ( current ) => current + 1 ); } ); setRegistryVersion( ( current ) => current + 1 ); isSubscribed = true; return true; } return false; }; if ( attemptSubscribe() === false && typeof window !== 'undefined' ) { pollHandle = window.setInterval( () => { if ( attemptSubscribe() && pollHandle !== null ) { window.clearInterval( pollHandle ); pollHandle = null; } }, 250 ); } return () => { if ( pollHandle !== null && typeof window !== 'undefined' ) { window.clearInterval( pollHandle ); } if ( isSubscribed && typeof unsubscribe === 'function' ) { unsubscribe(); } }; }, [] ); const fillProps = useMemo( () => ( { assetsFolder, getCachedData, setCachedData, } ), [ assetsFolder, getCachedData, setCachedData ] ); const registeredScreens = useMemo( () => { const { getRegisteredABTestsScreens } = getAnalyticsAbTestsAPI(); if ( typeof getRegisteredABTestsScreens === 'function' ) { return getRegisteredABTestsScreens().filter( ( FillComponent: any ) => typeof FillComponent === 'function' ); } return []; }, [ registryVersion ] ); const hasCustomScreen = registeredScreens.length > 0; const { ABTestsSlot: SlotComponent } = getAnalyticsAbTestsAPI(); const canRenderSlot = hasCustomScreen && typeof SlotComponent === 'function'; return ( <> { registeredScreens.map( ( FillComponent, index ) => ( ) ) } { canRenderSlot ? ( ) : ( ) } ); }