/**
* WordPress dependencies
*/
import { SelectControl } from '@safe-wordpress/components';
import { useSelect } from '@safe-wordpress/data';
import { _x, sprintf } from '@safe-wordpress/i18n';
/**
* External dependencies
*/
import { find, isArray, map, noop } from 'lodash';
import { store as NAB_EXPERIMENTS } from '@nab/experiments';
import { isEmpty } from '@nab/utils';
import type { ExperimentTypeName, Maybe } from '@nab/types';
export type PresetAlternativeProps = {
readonly experimentType: ExperimentTypeName;
readonly value: Maybe< string >;
readonly onChange: ( val: Maybe< Value > ) => void;
readonly collection?: 'default' | 'nab-check-availability' | string;
readonly disabled?: boolean;
readonly additionalValues?: {
readonly before?: ReadonlyArray< Value >;
readonly after?: ReadonlyArray< Value >;
};
readonly exclusions?: ReadonlyArray< string >;
readonly labels?: {
readonly selection?: string;
readonly selectAction?: string;
readonly loading?: string;
readonly empty?: string;
readonly unknownOption?: string;
};
};
type Value = {
readonly value: string;
readonly label: string;
readonly disabled?: boolean;
};
export const PresetAlternative = (
props: PresetAlternativeProps
): JSX.Element => {
const {
experimentType,
collection = 'default',
value,
disabled,
onChange,
additionalValues,
exclusions = [],
labels: {
selection = '',
selectAction: selectActionText,
loading: loadingPlaceholder = _x(
'Loading…',
'text',
'nelio-ab-testing'
),
empty: emptyPlaceholder = _x(
'No options available',
'text',
'nelio-ab-testing'
),
unknownOption: unknownOptionWarning = _x(
'Option not found',
'text',
'nelio-ab-testing'
),
} = {},
} = props;
const presetAlternatives = usePresetAlternatives(
experimentType,
collection,
additionalValues,
exclusions
);
if ( ! presetAlternatives ) {
return (
);
}
if ( isEmpty( presetAlternatives ) ) {
return (
);
}
let options = presetAlternatives;
if ( value && ! map( options, 'value' ).includes( value ) ) {
options = [
{
value,
label: !! selection
? sprintf(
/* translators: %1$s: Unknown option message as in “Option not found”. %2$s: Option name as, for instance, “Twenty Nineteen”. */
_x(
'%1$s (%2$s)',
'text (invalid option)',
'nelio-ab-testing'
),
unknownOptionWarning,
selection
)
: unknownOptionWarning,
},
...options,
];
}
if ( selectActionText ) {
options = [
{
disabled: true,
value: '_nab_no_option_selected' as const,
label: selectActionText,
},
...options,
];
}
return (
onChange( find( presetAlternatives, { value: id } ) )
}
options={ options }
disabled={ disabled }
/>
);
};
// =====
// HOOKS
// =====
function usePresetAlternatives(
experimentType: ExperimentTypeName,
collection: string,
additionalValues: PresetAlternativeProps[ 'additionalValues' ],
exclusions: ReadonlyArray< string >
): Maybe< ReadonlyArray< Value > > {
const presetAlts = useSelect(
( select ) => {
const { getExperimentSupport } = select( NAB_EXPERIMENTS );
const presetAlternatives = getExperimentSupport(
experimentType,
'presetAlternatives'
);
return presetAlternatives?.( select, collection );
},
[ collection, experimentType ]
);
const { before = [], after = [] } = additionalValues ?? {};
if ( ! isArray( presetAlts ) ) {
return before.length + after.length
? [ ...before, ...after ]
: undefined;
}
const result =
before.length + after.length
? [
...before,
...( presetAlts as ReadonlyArray< Value > ),
...after,
]
: ( presetAlts as ReadonlyArray< Value > );
return exclusions.length
? result.filter( ( a ) => ! exclusions.includes( a.value ) )
: result;
}