/** * WordPress dependencies */ import { SelectControl, TextControl } from '@safe-wordpress/components'; import { useDispatch } from '@safe-wordpress/data'; import { useState } from '@safe-wordpress/element'; import { _x } from '@safe-wordpress/i18n'; /** * External dependencies */ import clsx from 'clsx'; import { keys } from 'lodash'; import { ErrorText } from '@nab/components'; import { usePluginSetting } from '@nab/data'; import { createScopeRule, isUrlFragmentInvalid, getLocalUrlError, } from '@nab/utils'; import type { CustomUrlScopeRule, ScopeRuleId } from '@nab/types'; /** * Internal dependencies */ import { store as NAB_EDITOR } from '../../../store'; export type CustomUrlScopeProps = { readonly rules: ReadonlyArray< CustomUrlScopeRule >; readonly scopeSupport: 'urls-with-tested-post' | 'urls'; }; export const CustomUrlScope = ( { rules, scopeSupport, }: CustomUrlScopeProps ): JSX.Element => { const [ newRule, setNewRule ] = useState( createScopeRule( { type: 'partial', value: '' } ) as CustomUrlScopeRule ); const { setScopeRules } = useDispatch( NAB_EDITOR ); const editRule = ( id: ScopeRuleId, attributes: CustomUrlScopeRule[ 'attributes' ] ) => { const isNewRule = newRule.id === id; if ( isNewRule ) { setNewRule( createScopeRule( { type: 'partial', value: '', } ) as CustomUrlScopeRule ); } const ruleToAdd = { ...newRule, attributes }; if ( isNewRule ) { void setScopeRules( [ ...rules, ruleToAdd ] ); } else { void setScopeRules( rules.map( ( r ) => ( r.id === id ? { ...r, attributes } : r ) ) ); } }; return ( <> ); }; // ============ // HELPER VIEWS // ============ const Explanation = ( { rules, scopeSupport, }: CustomUrlScopeProps ): JSX.Element => { if ( ! rules.length ) { return (

{ 'urls-with-tested-post' === scopeSupport ? _x( 'Variants will be visible on all the pages of your website, including that of the tested element.', 'user', 'nelio-ab-testing' ) : _x( 'Variants will be visible on all the pages of your website.', 'user', 'nelio-ab-testing' ) }{ ' ' } { _x( 'If you wish to limit its scope to certain pages only, use the following form to define the URLs in which the test should run.', 'user', 'nelio-ab-testing' ) }

); } return (

{ 'urls-with-tested-post' === scopeSupport ? _x( 'Variants will be visible on the tested element’s page, as well as pages matching one of the following criteria.', 'text', 'nelio-ab-testing' ) : _x( 'Variants will be visible only on pages matching one of the following criteria.', 'text', 'nelio-ab-testing' ) }{ ' ' } { _x( 'To remove one criterion, leave it empty and save the test.', 'user', 'nelio-ab-testing' ) }

); }; const RuleSettings = ( { attributes, setAttributes, }: { readonly attributes: CustomUrlScopeRule[ 'attributes' ]; readonly setAttributes: ( attrs: Partial< CustomUrlScopeRule[ 'attributes' ] > ) => void; } ): JSX.Element => { const error = useError( attributes.type, attributes.value ); return (
  • setAttributes( { type } ) } />
    setAttributes( { value } ) } />
  • ); }; // ===== // HOOKS // ===== function useError( type: CustomUrlScopeRule[ 'attributes' ][ 'type' ], value: string ): string { const homeUrl = usePluginSetting( 'homeUrl' ); switch ( type ) { case 'partial': case 'partial-not-included': return value ? isUrlFragmentInvalid( value ) || '' : ''; case 'exact': case 'different': return value ? getLocalUrlError( value, homeUrl ) || '' : ''; } } // ==== // DATA // ==== const OPTIONS_RECORD: Record< CustomUrlScopeRule[ 'attributes' ][ 'type' ], string > = { exact: _x( 'URL is', 'text', 'nelio-ab-testing' ), different: _x( 'URL is not', 'text', 'nelio-ab-testing' ), partial: _x( 'URL contains', 'text', 'nelio-ab-testing' ), 'partial-not-included': _x( 'URL does not contain', 'text', 'nelio-ab-testing' ), }; const OPTIONS = keys( OPTIONS_RECORD ) .map( ( value ) => value as CustomUrlScopeRule[ 'attributes' ][ 'type' ] ) .map( ( value ) => ( { label: OPTIONS_RECORD[ value ], value, } ) );