/** * 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 ]; }