import { Pencil } from 'lucide-react'; import { store as CoreDataStore } from '@wordpress/block-editor'; import { cloneBlock } from '@wordpress/blocks'; import { useDispatch, useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import StandaloneBlockPreview from '../../../../accelerate/components/StandaloneBlockPreview'; import { store } from '../../../../audiences/data'; import { Select as AudiencePicker } from '../../../../audiences/ui'; import { ABTest, BlockAnalytics } from '../../../../global'; import { compactMetric, getLift } from '../../../../utils'; import { getP2BB } from '../../../../utils/admin'; import Title from '../../variant/components/Title'; import { Button } from '@/components/ui/button'; const defaultAnalytics = { loads: 0, views: 0, conversions: 0, unique: { loads: 0, views: 0, conversions: 0, }, }; interface VariantRowProps { analytics: BlockAnalytics, blockType: 'abtest' | 'personalization' | 'standard', index: number, isSelected: boolean, test: ABTest, variant: any, variants: any[], onSelectVariant: ( index: number ) => void, onAddBlankVariant?: () => void, } export default function VariantRow( props: VariantRowProps ) { const { analytics, blockType, index, isSelected, test, variant, variants, onSelectVariant, onAddBlankVariant, } = props; const { attributes, clientId, innerBlocks } = variant; const { insertBlock, removeBlock, updateBlockAttributes } = useDispatch( CoreDataStore ); // Retrieve the audience if this is a personalised block. const audience = useSelect( select => { if ( blockType !== 'personalization' ) { return null; } return select( store ).getPost( attributes.audience ); }, [ blockType, attributes?.audience ] ); // Finding the correct analytics data for the current variant is a little tricky, as the variant id is different for abtests or personalization blocks. // AB tests are index-based, incrementing integer from 0. The fallback is id: 0, etc. So, we have to use the current row index (props.index) to find the corrosponding analytics data. // Personalization blocks are are id-based whereby the variant ID is the audience ID. let rowAnalytics; if ( blockType === 'abtest' ) { rowAnalytics = ( analytics?.variants && analytics?.variants.find( variant => variant.id === index ) ) || defaultAnalytics; } else if ( blockType === 'personalization' ) { const audienceId = attributes?.audience ?? 0; rowAnalytics = ( analytics?.variants && analytics?.variants.find( v => v.id === audienceId ) ) || defaultAnalytics; } else { rowAnalytics = defaultAnalytics; } const fallbackAnalytics = ( analytics?.variants && analytics?.variants.find( variant => variant.id === 0 ) ) || defaultAnalytics; const baseConversionRate = ( fallbackAnalytics?.unique?.views || 0 ) > 0 ? ( fallbackAnalytics.unique.conversions / fallbackAnalytics.unique.views ) * 100 : 0; const conversionRate = ( rowAnalytics?.unique?.views || 0 ) > 0 ? ( rowAnalytics.unique.conversions / rowAnalytics.unique.views ) * 100 : 0; const lift = getLift( conversionRate, baseConversionRate ); // Probability to be best. const maxRate = ( test?.results?.variants || [] ).reduce( ( carry: number, variant: { rate: number } ) => { return variant.rate > carry ? variant.rate : carry; }, 0 ); const result = test?.results?.variants[ index ] || { p: 0, rate: 0, }; const p2bb = getP2BB( result.p ); // result.p is now P2BB directly const hasNoViews = ( rowAnalytics?.unique?.views || 0 ) === 0; const duplicateVariant = async ( e: React.MouseEvent ) => { e.preventDefault(); const newVariant = cloneBlock( variant, { fallback: false, audience: null, title: null, } ); await insertBlock( newVariant, index + 1 ); }; return ( 0 ? 'border-t' : '' }` } style={ index > 0 ? { borderTopColor: '#ddd' } : {} } onClick={ () => onSelectVariant( index ) } >
EDITING
{ ( blockType === 'personalization' && index !== 0 /* fallback */ ) ? ( ( attributes.audience ? (