/** * WordPress dependencies */ import { useSelect } from '@safe-wordpress/data'; import { _x, sprintf } from '@safe-wordpress/i18n'; /** * External dependencies */ import clsx from 'clsx'; import { store as NAB_DATA } from '@nab/data'; import type { EntityId, EntityKindName, Maybe } from '@nab/types'; /** * Internal dependencies */ import './style.scss'; import { PostOption } from './post-option'; import { useOptionLoader } from '../utils'; import { AsyncSelectControl } from '../../async-select-control'; import type { PostSearcherProps } from '../types'; export const SingularPostSearcher = ( { id, className, disabled, onChange, placeholder: defaultPlaceholder, value, type = 'post', menuPlacement, menuShouldBlockScroll, ...loaderProps }: PostSearcherProps< EntityId, Maybe< EntityId > > ): JSX.Element => { const { post, isLoading } = usePost( type, value ); const placeholder = usePlaceholder( { type, id: value }, defaultPlaceholder ); const label = post?.title; const selectedOption = ! isLoading && value ? { type, value, label: label ?? '' } : undefined; const loadOptions = useOptionLoader( { ...loaderProps, type } ); return ( onChange( option?.value ) } additional={ { page: 1 } } placeholder={ placeholder } menuPlacement={ menuPlacement } menuShouldBlockScroll={ menuShouldBlockScroll } /> ); }; // ===== // HOOKS // ===== const usePost = ( type: EntityKindName, value: EntityId = 0 ): { readonly post: { readonly id: EntityId; readonly title: string }; readonly isLoading: boolean; } => { const post = useSelect( ( select ) => select( NAB_DATA ).getEntityRecord( type, value ) || { id: value, title: sprintf( getElementNotFound( type ), value ), }, [ type, value ] ); const isLoading = useSelect( ( select ) => ! select( NAB_DATA ).hasFinishedResolution( 'getEntityRecord', [ type, value, ] ) && ! select( NAB_DATA ).hasResolutionFailed( 'getEntityRecord', [ type, value, ] ), [ type, value ] ); return { post, isLoading }; }; function usePlaceholder( { type, id }: { type: EntityKindName; id?: EntityId }, defaultPlaceholder?: string ): string { const { isLoading } = usePost( type, id ); if ( isLoading ) { return _x( 'Loading…', 'text', 'nelio-ab-testing' ); } if ( defaultPlaceholder ) { return defaultPlaceholder; } switch ( type ) { case 'page': return _x( 'Select a page…', 'user', 'nelio-ab-testing' ); case 'post': return _x( 'Select a post…', 'user', 'nelio-ab-testing' ); case 'product': return _x( 'Select a product…', 'user', 'nelio-ab-testing' ); default: return _x( 'Select…', 'user', 'nelio-ab-testing' ); } } function getElementNotFound( type: EntityKindName ): string { switch ( type ) { case 'page': /* translators: %d: Page id. */ return _x( 'Page #%d not found', 'text', 'nelio-ab-testing' ); case 'post': /* translators: %d: Post id. */ return _x( 'Post #%d not found', 'text', 'nelio-ab-testing' ); case 'product': /* translators: %d: Product id. */ return _x( 'Product #%d not found', 'text', 'nelio-ab-testing' ); default: /* translators: %d: Item id. */ return _x( 'Content #%d not found', 'text', 'nelio-ab-testing' ); } }