import { store as BlockEditorStore } from '@wordpress/block-editor'; import { BlockInstance, createBlock } from '@wordpress/blocks'; import { Icon, Tooltip } from '@wordpress/components'; import { store as CoreDataStore } from '@wordpress/core-data'; import { useSelect, useDispatch, useRegistry, select } from '@wordpress/data'; import { useState } from '@wordpress/element'; import { __, _n } from '@wordpress/i18n'; import { info, chartBar, trendingUp } from '@wordpress/icons'; import { store as PreferencesStore } from '@wordpress/preferences'; import { HeaderRow, VerticalDivider } from '../../../../accelerate/components/shared/HeaderRow'; import { PeriodChips } from '../../../../accelerate/components/shared/PeriodChips'; import { ViewsMetric } from '../../../../accelerate/components/shared/ViewsMetric'; import { store as AnalyticsStore } from '../../../../blocks/data'; import { useCurrentPostId } from '../../../../data/hooks'; import { store } from '../../../../data/index'; import { BlockAnalytics } from '../../../../global'; import { compactMetric, Post } from '../../../../utils/admin'; import ABTestResult from './ABTestResult'; import VariantRow from './VariantRow'; import { Button } from '@/components/ui/button'; const PERIODS = [ 'P7D', 'P30D', 'P90D' ] as const; type Period = ( typeof PERIODS )[number]; export const Header = () => { const registry = useRegistry(); const { set: setPreference } = useDispatch( PreferencesStore ); const { insertBlock, removeBlocks, clearSelectedBlock, selectBlock, } = useDispatch( BlockEditorStore ); const { editEntityRecord } = useDispatch( CoreDataStore ); const postId = useCurrentPostId(); const post = useCurrentPost(); const blockType = post ? post.blockType : undefined; const abTests = post ? ( post.ab_tests || {} ) : {}; const test = ( abTests as any )?.block || { start_time: 0 }; const startTime = test?.start_time; const [ period, setPeriod ] = useState( 'P7D' ); const histogram = useSelect( select => { if ( ! postId ) { return {}; } const args = { ids: [ postId ] } as any; if ( blockType === 'abtest' ) { // All-time for A/B: since test start args.start = new Date( startTime ).toISOString(); } else if ( blockType === 'personalization' ) { // All-time for personalization: since block creation const created = post && ( post as any ).date ? new Date( ( post as any ).date ).toISOString() : undefined; if ( created ) args.start = created; } else { // Standard blocks respect the selected period args.period = period; } return select( store ).getDiffs( args ); }, [ postId, period, startTime, blockType, post && ( post as any ).date ] ); const analytics: BlockAnalytics = useSelect( select => { if ( ! postId ) { return null; } const args: Record = {}; if ( blockType === 'abtest' ) { args.start = new Date( startTime ).toISOString(); } else { args.period = period; } return select( AnalyticsStore ).getViews( postId, args ); }, [ postId, period, startTime, blockType ] ); const [ blocks ] = useSelect( select => { return [ select( BlockEditorStore ).getBlocks() as BlockInstance[] ]; }, [ blockType ] ); // Global diffs loading state to avoid flicker while switching periods. const isLoadingDiffs = useSelect( select => select( store ).getIsLoadingDiffs(), [] ); const variants = blocks.filter( block => block.name === 'altis/variant' ); const selectedVariant: number = useSelect( select => { const pref = select( PreferencesStore ).get( 'altis/global-blocks', `${ postId }:variant` ) || 0; // The preference stores the WordPress block index, find which variant has that block index const { getBlockIndex } = select( BlockEditorStore ); const arrayIndex = variants.findIndex( v => { const blockIndex = getBlockIndex( v.clientId ); return blockIndex === pref; } ); return arrayIndex >= 0 ? arrayIndex : 0; }, [ postId, variants ] ); // Header expansion controls. const variantsExpanded = useSelect( select => { const value = select( PreferencesStore ).get( 'altis/global-blocks', 'variantsExpanded' ); if ( value !== undefined ) { return value; } // Default to expanded if no preference is set return true; }, [] ); if ( ! postId ) { return null; } if ( ! post ) { return null; } const setVariantsExpanded = ( expanded: boolean ) => { setPreference( 'altis/global-blocks', 'variantsExpanded', expanded ); }; const updateBlockPost = ( edits: any ) => { editEntityRecord( 'postType', 'wp_block', postId, edits, { undoIgnore: false, } ); }; const convertToAbTest = () => { setPeriod( 'P7D' ); registry.batch( () => { updateBlockPost( { blockType: 'abtest', ab_tests: { ...abTests, block: { started: false, paused: true, ended: false, start_time: Date.now(), end_time: Date.now() + ( 90 * 24 * 60 * 60 * 1000 ), traffic_percentage: 100, variant_traffic_percentage: [], results: { timestamp: 0, winner: null, winning: null, aggs: [], variants: [], }, }, }, } ); removeBlocks( blocks.map( b => b.clientId ) ); const newVariant = createBlock( 'altis/variant', { fallback: true, title: __( 'Variant A', 'altis' ), }, blocks ); insertBlock( newVariant, 0, '' ); } ); }; const convertToPersonalization = () => { setPeriod( 'P7D' ); registry.batch( () => { updateBlockPost( { blockType: 'personalization', ab_tests: { ...abTests, block: { started: false, paused: true, ended: false, start_time: Date.now(), end_time: Date.now() + ( 90 * 24 * 60 * 60 * 1000 ), traffic_percentage: 100, variant_traffic_percentage: [], results: { timestamp: 0, winner: null, winning: null, aggs: [], variants: [], }, }, }, } ); removeBlocks( blocks.map( b => b.clientId ) ); const newVariant = createBlock( 'altis/variant', { fallback: true, title: __( 'Fallback', 'altis' ), }, blocks ); insertBlock( newVariant, 0, '' ); } ); }; const addBlankVariant = () => { // Create a default paragraph block to put inside the variant so it's immediately editable const defaultParagraph = createBlock( 'core/paragraph' ); const newVariant = createBlock( 'altis/variant', { fallback: false, }, [ defaultParagraph ] ); insertBlock( newVariant, blocks.length, '' ); // Set the preference to point to the new variant setTimeout( () => { const { getBlockIndex } = select( BlockEditorStore ); const actualBlockIndex = getBlockIndex( newVariant.clientId ); setPreference( 'altis/global-blocks', `${ postId }:variant`, actualBlockIndex ); selectBlock( newVariant.clientId ); }, 100 ); }; return ( <> { blockType === 'standard' && (
{ __( 'Global Block', 'altis' ) }
) } { blockType === 'standard' && ( ) } { blockType !== 'standard' && ( ) } { blockType !== 'standard' && ( ) } { blockType === 'standard' ? ( ) : (
{ __( 'All‑time', 'altis' ) }
) } { analytics && (
{ __( 'Conversion', 'altis' ) } { ( analytics.unique.views || 0 ) > 0 ? compactMetric( ( analytics.unique.conversions / analytics.unique.views ) * 100, '%' ) : '—' }
) } { blockType === 'standard' && ( ) } { blockType === 'standard' && (
{ __( 'Convert to', 'altis' ) }
) }
{ blockType === 'abtest' && } { blockType !== 'standard' && (
{ blockType === 'personalization' && ( ) } { blockType === 'abtest' && ( ) } { variants.map( ( variant, index ) => { return ( { if ( variants[variantIndex] ) { const targetClientId = variants[variantIndex].clientId; // Get the WordPress block index and set preference manually const { getBlockIndex } = select( BlockEditorStore ); const actualBlockIndex = getBlockIndex( targetClientId ); setPreference( 'altis/global-blocks', `${ postId }:variant`, actualBlockIndex ); selectBlock( targetClientId ); } } } /> ); } ) }
  { __( 'Variant Name', 'altis' ) }
{ __( 'Coverage', 'altis' ) }
{ __( 'Conversion Rate', 'altis' ) }
{ __( 'Improvement', 'altis' ) }
{ __( 'Probability to be Best', 'altis' ) }
) } ); }; const useCurrentPost = (): Post | false => { const postId = useCurrentPostId(); return useSelect( select => { if ( ! postId ) { return false; } return select( CoreDataStore ).getEditedEntityRecord( 'postType', 'wp_block', postId ); }, [ postId ] ) as Post | false; };