/**
* WordPress dependencies
*/
import { Dashicon } from '@safe-wordpress/components';
import { useDispatch, useSelect } from '@safe-wordpress/data';
import { createInterpolateElement, useEffect } from '@safe-wordpress/element';
import { _x, sprintf } from '@safe-wordpress/i18n';
/**
* External dependencies
*/
import { findIndex } from 'lodash';
import { v4 as uuid } from 'uuid';
import { store as NAB_EXPERIMENTS } from '@nab/experiments';
import { createGoal } from '@nab/utils';
import type { Goal as RealGoal, GoalId, Maybe } from '@nab/types';
type Goal = Omit< RealGoal, 'conversionActions' >;
/**
* Internal dependencies
*/
import './style.scss';
import { Goal as GoalView } from '../goal';
import { GoalList } from '../goal-list';
import { useExperimentAttribute } from '../hooks';
import { ReusableGoalDialog } from '../reusable-goal-dialog';
import { store as NAB_EDITOR } from '../../store';
export const GoalSection = (): JSX.Element => {
useAutoConversionActionsEffect();
const goal = useActiveGoal();
const goals = useGoals();
const isExperimentPaused = useIsExperimentPaused();
const numberOfGoals = goals.length;
const isAutomatic = useIsActiveGoalAutomatic();
const {
addGoals,
removeGoals,
setActiveGoal,
updateGoal,
addConversionActionsIntoGoal,
} = useDispatch( NAB_EDITOR );
const canGoalBeRemoved = 1 < numberOfGoals && ! isExperimentPaused;
const canGoalBeDuplicated = ! isExperimentPaused;
const removeActiveGoal = () => {
if ( ! goal ) {
return;
}
const nextGoal = getAdjacentGoal( goals, goal.id );
if ( ! nextGoal ) {
return;
}
void setActiveGoal( nextGoal.id );
void removeGoals( goal.id );
};
const updateActiveGoal = ( attributes: Partial< Goal[ 'attributes' ] > ) =>
goal && updateGoal( goal.id, { ...goal.attributes, ...attributes } );
const actions = useConversionActions( goal?.id );
const duplicateGoal = () => {
if ( ! goal ) {
return;
}
const newGoal = {
...createGoal(),
attributes: {
...goal.attributes,
name: goal.attributes.name
? sprintf(
/* translators: %s: Name of an item being duplicated. */
_x( 'Copy of %s', 'text', 'nelio-ab-testing' ),
goal.attributes.name
)
: '',
},
};
const newActions = actions.map( ( a ) => ( { ...a, id: uuid() } ) );
void addGoals( newGoal );
void addConversionActionsIntoGoal( newGoal.id, newActions );
};
return (
{ createInterpolateElement(
sprintf(
/* translators: %s: Dashicon. */
_x(
'%s Conversion Goals and Actions',
'text',
'nelio-ab-testing'
),
''
),
{
icon: (
),
}
) }
updateActiveGoal( { name } ) }
duplicateGoal={
goal && canGoalBeDuplicated ? duplicateGoal : undefined
}
removeGoal={
canGoalBeRemoved ? removeActiveGoal : undefined
}
isAutomatic={ isAutomatic }
/>
);
};
// =====
// HOOKS
// =====
const useActiveGoal = () =>
useSelect( ( select ) => select( NAB_EDITOR ).getActiveGoal(), [] );
const useGoals = () =>
useSelect( ( select ) => select( NAB_EDITOR ).getGoals(), [] );
const useIsExperimentPaused = () => {
const [ status ] = useExperimentAttribute( 'status' );
return ( status || '' ).includes( 'paused' );
};
const useIsActiveGoalAutomatic = () => {
const goal = useActiveGoal();
const goals = useGoals();
const firstGoal = goals[ 0 ];
return useSelect(
( select ): boolean => {
const { getExperimentType } = select( NAB_EDITOR );
const { hasExperimentSupport } = select( NAB_EXPERIMENTS );
return (
goal?.id === firstGoal?.id &&
hasExperimentSupport(
getExperimentType(),
'automaticGoalSetup'
)
);
},
[ goal, firstGoal ]
);
};
const useAutoConversionActionsEffect = () => {
const { replaceConversionActionsInGoal } = useDispatch( NAB_EDITOR );
const goalId = useGoals()[ 0 ]?.id;
const control = useSelect(
( select ) => select( NAB_EDITOR ).getAlternative( 'control' ),
[]
);
const automaticGoalSetup = useSelect( ( select ) => {
const { getExperimentType } = select( NAB_EDITOR );
const { getExperimentSupport } = select( NAB_EXPERIMENTS );
return getExperimentSupport(
getExperimentType(),
'automaticGoalSetup'
);
}, [] );
useEffect( () => {
if ( ! control || ! goalId || ! automaticGoalSetup ) {
return;
}
const auto = automaticGoalSetup( control.attributes );
void replaceConversionActionsInGoal( goalId, auto );
}, [
control,
goalId,
automaticGoalSetup,
replaceConversionActionsInGoal,
] );
};
const useConversionActions = ( id: GoalId | undefined ) =>
useSelect(
( select ) =>
id ? select( NAB_EDITOR ).getConversionActions( id ) : [],
[ id ]
);
// =======
// HELPERS
// =======
function getAdjacentGoal(
goals: ReadonlyArray< Goal >,
goalId: GoalId
): Maybe< Goal > {
const index = findIndex( goals, { id: goalId } );
if ( index === goals.length - 1 ) {
return goals[ index - 1 ];
}
return goals[ index + 1 ];
}