/** * WordPress dependencies */ // eslint-disable-next-line import/named import { BlockInstance, getBlockType } from '@wordpress/blocks'; import { Button, Dashicon, __experimentalDivider as Divider, KeyboardShortcuts, Tooltip, } from '@wordpress/components'; import { select as selectFn, useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { arrowLeft, arrowRight, calendar, check, closeSmall, external, Icon, page, people, post, postAuthor, seen, } from '@wordpress/icons'; /** * Internal dependencies */ import { GutenbergFunction } from '../../../../@types/gutenberg/types'; import { Thumbnail } from '../../../common/components/thumbnail'; import { getSmartShortDate } from '../../../common/utils/date'; import { formatToImpreciseNumber } from '../../../common/utils/number'; import { InboundSmartLink, SmartLink } from '../provider'; import { BlockPreview } from './component-block-preview'; import { InboundLinkDetails } from './component-inbound-link'; /** * The props for the SuggestionBreadcrumb component. * * @since 3.16.0 */ type SuggestionBreadcrumbProps = { link: SmartLink, }; /** * Displays the breadcrumb for the suggestion. * * It shows the parent blocks of the block where the link is found. * * @since 3.16.0 * * @param {SuggestionBreadcrumbProps} props The component's props. */ const SuggestionBreadcrumb = ( { link }: SuggestionBreadcrumbProps ): React.JSX.Element => { const blockId = link.match?.blockId; // Fetch block details and parent IDs using the blockId. const { block, parents } = useSelect( ( select ) => { const { getBlock, getBlockParents } = select( 'core/block-editor' ) as GutenbergFunction; if ( ! blockId ) { return { block: undefined, parents: [] }; } return { block: getBlock( blockId ), parents: getBlockParents( blockId ) .map( ( id ) => getBlock( id ) ) .filter( ( currBlock ): currBlock is BlockInstance => currBlock !== undefined ), }; }, [ blockId ], ); if ( ! block ) { return <>; } return (
{ parents.map( ( parent: BlockInstance, index: number ) => ( { getBlockType( parent.name )?.title }  /  ) ) } { getBlockType( block.name )?.title } { block.attributes?.metadata?.name && ( { block.attributes.metadata.name } ) }
); }; /** * The LinkDetails component, which renders the details of the link suggestion. * * @since 3.16.0 * @since 3.18.0 Added the post type to the link details. * * @param {{link: SmartLink}} props The component's props. */ const LinkDetails = ( { link }: { link: SmartLink } ): React.JSX.Element => { const author = link.wp_post_meta?.author ?? __( 'N/A', 'wp-parsely' ); const avgEngaged = link.post_stats?.avg_engaged ?? __( 'N/A', 'wp-parsely' ); const date = link.wp_post_meta?.date ? getSmartShortDate( new Date( link.wp_post_meta.date ) ) : __( 'N/A', 'wp-parsely' ); const thumbnail = link.wp_post_meta?.thumbnail ?? false; const title = link.wp_post_meta?.title ?? __( 'N/A', 'wp-parsely' ); const type = link.wp_post_meta?.type ?? __( 'External', 'wp-parsely' ); const url = link.wp_post_meta?.url; // Used for the link button. const views = link.post_stats?.views ? formatToImpreciseNumber( link.post_stats.views ) : __( 'N/A', 'wp-parsely' ); const visitors = link.post_stats?.visitors ? formatToImpreciseNumber( link.post_stats.visitors ) : __( 'N/A', 'wp-parsely' ); return (
{ thumbnail ? ( ) : ( ) }
{ title } { url && ( ) }
{ date }
{ author }
{ type }
{ link.post_stats && (
{ views && (
{ views }
) } { visitors && (
{ visitors }
) } { avgEngaged && (
{ avgEngaged }
) }
) }
); }; /** * The props for the ReviewSuggestion component. * * @since 3.16.0 */ type ReviewSuggestionProps = { link: SmartLink, onNext: () => void, onPrevious: () => void, onAccept: () => void, onReject: () => void, onRemove: () => void, onSelectInEditor: () => void, hasPrevious: boolean, hasNext: boolean, }; /** * The ReviewSuggestion component, which renders the review suggestion UI. * * @since 3.16.0 * * @param {ReviewSuggestionProps} props The component's props. */ export const ReviewSuggestion = ( { link, onNext, onPrevious, onAccept, onReject, onRemove, onSelectInEditor, hasPrevious, hasNext, }: ReviewSuggestionProps ): React.JSX.Element => { // If the link is a Inbound Link, render the InboundLinkDetails component. if ( link && ( link as InboundSmartLink ).post_data !== undefined ) { return ; } if ( ! link?.match ) { return <>{ __( 'This Smart Link does not have any matches in the current content.', 'wp-parsely' ) }; } const blockId = link.match.blockId; // Get the block. const block = selectFn( 'core/block-editor' ).getBlock( blockId ); const isApplied = link.applied; if ( ! block ) { return <>{ __( 'No block is selected.', 'wp-parsely' ) }; } return (
{ if ( link && ! link.applied ) { onAccept(); } }, r: () => { if ( ! link ) { return; } if ( link.applied ) { onRemove(); } else { onReject(); } }, } } />
{ ! isApplied && ( <> ) } { isApplied && ( <> ) }
); };