Back

0% Statements 0/33
0% Branches 0/18
0% Functions 0/7
0% Lines 0/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88                                                                                                                                                                               
import { Button } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { useCallback, useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { acceptSectionSuggestion } from '../lib/dom';
import { recordGuidelinesEvent } from '../lib/tracks';
import { AI_STORE_NAME } from '../store';
import DiffView from './diff-view';
 
export default function SuggestionActions( { slug } ) {
	const suggestion = useSelect( select => select( AI_STORE_NAME ).getSuggestion( slug ), [ slug ] );
	const sectionLoading = useSelect(
		select => select( AI_STORE_NAME ).isSectionLoading( slug ),
		[ slug ]
	);
	const { clearSuggestion } = useDispatch( AI_STORE_NAME );
 
	const [ original, setOriginal ] = useState( '' );
	const [ textareaHeight, setTextareaHeight ] = useState( null );
 
	// Direct DOM class manipulation is necessary because this component is rendered in
	// a separate React root injected into Gutenberg's page — we can't control classes
	// on Gutenberg-owned elements through React props.
	useEffect( () => {
		const item = document.querySelector( `.guidelines__list-item[data-slug="${ slug }"]` );
		const form = item?.querySelector( 'form' );
		if ( ! form ) {
			return;
		}
 
		// Capture textarea draft and height before hiding it.
		if ( suggestion && ! form.classList.contains( 'has-jetpack-suggestion' ) ) {
			const textarea = form.querySelector( 'textarea' );
			if ( textarea ) {
				setOriginal( textarea.value || '' );
				if ( textarea.offsetHeight > 0 ) {
					setTextareaHeight( textarea.offsetHeight );
				} else {
					// Fallback when textarea is hidden (e.g. collapsed accordion).
					// Compute height from rows attribute to match the textarea.
					const rows = parseInt( textarea.getAttribute( 'rows' ), 10 ) || 4;
					// line-height: 20px, padding: 9px top + 9px bottom, border: 1px + 1px.
					setTextareaHeight( rows * 20 + 20 );
				}
			}
		}
 
		form.classList.toggle( 'has-jetpack-suggestion', !! suggestion );
		form.classList.toggle( 'is-jetpack-loading', sectionLoading && ! suggestion );
		return () => {
			form.classList.remove( 'has-jetpack-suggestion', 'is-jetpack-loading' );
		};
	}, [ slug, suggestion, sectionLoading ] );
 
	const handleAccept = useCallback( () => {
		recordGuidelinesEvent( 'accept', { type: 'section', slug } );
		acceptSectionSuggestion( slug, suggestion, clearSuggestion );
	}, [ slug, suggestion, clearSuggestion ] );
 
	const handleDismiss = useCallback( () => {
		recordGuidelinesEvent( 'dismiss', { type: 'section', slug } );
		clearSuggestion( slug );
	}, [ slug, clearSuggestion ] );
 
	if ( ! suggestion ) {
		return null;
	}
 
	return (
		<div className="jetpack-content-guidelines-ai__suggestion">
			<DiffView
				original={ original }
				suggestion={ suggestion }
				onAccept={ handleAccept }
				height={ textareaHeight }
			/>
			<div className="jetpack-content-guidelines-ai__suggestion-actions">
				<Button variant="primary" onClick={ handleAccept }>
					{ __( 'Accept suggestion', 'jetpack' ) }
				</Button>
				<Button variant="tertiary" onClick={ handleDismiss }>
					{ __( 'Dismiss', 'jetpack' ) }
				</Button>
			</div>
		</div>
	);
}