Skip to content

Commit

Permalink
AI Title Optimization: Add modal content (#37003)
Browse files Browse the repository at this point in the history
* AI Title: Add modal content and options

* changelog

* AI Title: Fix whitespace

* AI Title: Avoid calling map directly
  • Loading branch information
renatoagds authored Apr 24, 2024
1 parent 734e054 commit 78533e8
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: other

Add title optimization modal content
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,18 @@ export default function AiAssistantModal( {
hideHeader = true,
requestingState = 'init',
title = __( 'AI Assistant', 'jetpack' ),
maxWidth = 720,
}: {
children: React.ReactNode;
handleClose: () => void;
hideHeader?: boolean;
requestingState?: RequestingStateProp;
title?: string;
maxWidth?: number;
} ) {
return (
<Modal __experimentalHideHeader={ hideHeader } className="ai-assistant-modal">
<div className="ai-assistant-modal__content">
<div className="ai-assistant-modal__content" style={ { maxWidth } }>
<ModalHeader requestingState={ requestingState } onClose={ handleClose } title={ title } />
<hr className="ai-assistant-modal__divider" />
{ children }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
display: flex;
flex-direction: column;
width: 100vw;
max-width: 720px;
}

&__header {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
/**
* External dependencies
*/
import { Button } from '@wordpress/components';
import { useAiSuggestions } from '@automattic/jetpack-ai-client';
import { Button, Spinner } from '@wordpress/components';
import { useState, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import usePostContent from '../../hooks/use-post-content';
import AiAssistantModal from '../modal';
import TitleOptimizationOptions from './title-optimization-options';
import './style.scss';

export default function TitleOptimization( {
busy,
Expand All @@ -14,26 +21,104 @@ export default function TitleOptimization( {
disabled: boolean;
} ) {
const modalTitle = __( 'Optimize post title', 'jetpack' );

const postContent = usePostContent();
const [ selected, setSelected ] = useState( 'title-0' );
const [ isTitleOptimizationModalVisible, setIsTitleOptimizationModalVisible ] = useState( false );
const [ generating, setGenerating ] = useState( false );
const [ options, setOptions ] = useState( [] );

const toggleTitleOptimizationModal = useCallback( () => {
setIsTitleOptimizationModalVisible( ! isTitleOptimizationModalVisible );
}, [ isTitleOptimizationModalVisible ] );

const handleDone = useCallback( ( content: string ) => {
setGenerating( false );
try {
const parsedContent = JSON.parse( content );
setOptions( parsedContent );
} catch ( e ) {
// Do nothing
}
}, [] );

const { request } = useAiSuggestions( {
onDone: handleDone,
onError: () => {
setGenerating( false );
},
} );

const handleRequest = useCallback( () => {
// Message to request a backend prompt for this feature
const messages = [
{
role: 'jetpack-ai' as const,
context: {
type: 'title-optimization',
content: postContent,
},
},
];

request( messages, { feature: 'jetpack-ai-title-optimization' } );
}, [ postContent, request ] );

const handleTitleOptimization = useCallback( () => {
setGenerating( true );
toggleTitleOptimizationModal();
handleRequest();
}, [ handleRequest, toggleTitleOptimizationModal ] );

return (
<div>
<p>{ __( 'Use AI to optimize key details of your post.', 'jetpack' ) }</p>
<Button
isBusy={ busy }
disabled={ disabled }
onClick={ toggleTitleOptimizationModal }
onClick={ handleTitleOptimization }
variant="secondary"
>
{ __( 'Improve title', 'jetpack' ) }
</Button>
{ isTitleOptimizationModalVisible && (
<AiAssistantModal handleClose={ toggleTitleOptimizationModal } title={ modalTitle }>
<p>{ __( 'This is the modal content.', 'jetpack' ) }</p>
<AiAssistantModal
handleClose={ toggleTitleOptimizationModal }
title={ modalTitle }
maxWidth={ 512 }
>
{ generating ? (
<div className="jetpack-ai-title-optimization__loading">
<Spinner
style={ {
width: '50px',
height: '50px',
} }
/>
{ __( 'Reading your post and generating suggestions…', 'jetpack' ) }
</div>
) : (
<>
<span className="jetpack-ai-title-optimization__intro">
{ __( 'Choose an optimized title below:', 'jetpack' ) }
</span>
<TitleOptimizationOptions
onChangeValue={ e => setSelected( e.target.value ) }
selected={ selected }
options={ options?.map?.( ( option, index ) => ( {
value: `title-${ index }`,
label: option.title,
description: option.explanation,
} ) ) }
/>
<div className="jetpack-ai-title-optimization__cta">
<Button variant="secondary" onClick={ toggleTitleOptimizationModal }>
{ __( 'Cancel', 'jetpack' ) }
</Button>
<Button variant="primary">{ __( 'Replace title', 'jetpack' ) }</Button>
</div>
</>
) }
</AiAssistantModal>
) }
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.jetpack-ai-title-optimization {
&__loading {
display: flex;
flex-direction: column;
gap: 16px;
width: 100%;
height: 200px;
align-items: center;
justify-content: center;
}

&__intro {
margin-top: 16px;
}

&__cta {
display: flex;
gap: 8px;
justify-content: flex-end;
align-items: center;
margin-top: 16px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.jetpack-ai-title-optimization__options {
margin-top: 16px;
}

.jetpack-ai-title-optimization__option {
display: flex;
justify-content: center;
align-items: start;
gap: 16px;
margin-bottom: 16px;

& > input {
margin-top: 8px;
}

&-content {
display: flex;
flex-direction: column;
}

&-label {
font-weight: 600;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Internal dependencies
*/
import './title-optimization-options.scss';

type TitleOptimizationOptions = {
value: string;
label: string;
description: string;
}[];

const id = 'title-optimization-option';

export default function TitleOptimizationOptions( {
options,
selected,
onChangeValue,
}: {
options: TitleOptimizationOptions;
selected: string;
onChangeValue: ( event: React.ChangeEvent< HTMLInputElement > ) => void;
} ) {
return (
<div className="jetpack-ai-title-optimization__options">
{ options.map( ( option, index ) => (
<div className="jetpack-ai-title-optimization__option" key={ `${ id }-${ index }` }>
<input
id={ `${ id }-${ index }` }
className="jetpack-ai-title-optimization__option-input"
type="radio"
name={ id }
value={ option.value }
onChange={ onChangeValue }
checked={ option.value === selected }
/>
<div className="jetpack-ai-title-optimization__option-content">
<label
className="jetpack-ai-title-optimization__option-label"
htmlFor={ `${ id }-${ index }` }
>
{ option.label }
</label>
<span className="jetpack-ai-title-optimization__option-description">
{ option.description }
</span>
</div>
</div>
) ) }
</div>
);
}

0 comments on commit 78533e8

Please sign in to comment.