/** * WordPress dependencies */ import { Button } from '@safe-wordpress/components'; import { useSelect, useDispatch } from '@safe-wordpress/data'; import { useCallback, useEffect } from '@safe-wordpress/element'; import { _x } from '@safe-wordpress/i18n'; /** * External dependencies */ import { isEqual, zip } from 'lodash'; import { AlternativeDistributionSetting } from '@nab/components'; import { usePluginSetting } from '@nab/data'; import { transformAlternativeChancesToAllocatedSlots } from '@nab/utils'; /** * Internal dependencies */ import './style.scss'; import { useExperimentAttribute } from '../hooks'; import { store as NAB_EDITOR } from '../../store'; export const AlternativeDistributionSection = (): JSX.Element | null => { const visible = usePluginSetting( 'isAlternativeDistributionAllowed' ); const alternatives = useAlternatives(); const { setAlternative } = useDispatch( NAB_EDITOR ); const maxCombinations = usePluginSetting( 'maxCombinations' ); const [ status ] = useExperimentAttribute( 'status' ); const isPaused = ( status || '' ).includes( 'paused' ); const readonly = isPaused; const distributeEvenly = useCallback( () => alternatives.some( ( a ) => a.attributes.chance ) && alternatives.forEach( ( a ) => setAlternative?.( a.id, { ...a, attributes: { ...a.attributes, chance: undefined }, } ) ), [ alternatives, setAlternative ] ); const updateCuts = useCallback( ( newCuts: ReadonlyArray< number > ) => { const evenCuts = getEvenCutDistribution( newCuts.length, maxCombinations ); if ( isEqual( newCuts, evenCuts ) ) { return distributeEvenly(); } const chances = newCuts.map( ( cut ) => Math.round( ( cut / maxCombinations ) * 100_00 ) / 100 ); const pairs = zip( alternatives, chances ); pairs.forEach( ( [ alternative, chance ] ) => { if ( ! alternative || ! chance ) { return; } void setAlternative( alternative.id, { ...alternative, attributes: { ...alternative.attributes, chance }, } ); } ); }, [ alternatives, maxCombinations, distributeEvenly, setAlternative ] ); useEffect( () => { if ( alternatives.length === maxCombinations ) { distributeEvenly(); } }, [ alternatives, maxCombinations, distributeEvenly ] ); if ( ! visible ) { return null; } return (

{ _x( 'Variant Distribution', 'text', 'nelio-ab-testing' ) }{ ' ' } { ! readonly && alternatives.some( ( a ) => a.attributes.chance ) && ( ) }

); }; // ===== // HOOKS // ===== const useAlternatives = () => useSelect( ( select ) => select( NAB_EDITOR ).getAlternatives(), [] ); // ======= // HELPERS // ======= function getEvenCutDistribution( size: number, slots: number ) { return transformAlternativeChancesToAllocatedSlots( new Array( size ).fill( 1 ), slots ); }