gutenberg_ai_tools-1.0.x-dev/blocks/ai-block/edit.js
blocks/ai-block/edit.js
/* eslint-disable-next-line import/no-unresolved */
import React, { useState } from 'react';
/* eslint-disable-next-line import/no-unresolved */
import { PanelBody, PanelRow, TextareaControl } from '@wordpress/components';
import {
useBlockProps,
BlockControls,
InnerBlocks,
InspectorControls,
RichText,
/* eslint-disable-next-line import/no-unresolved */
} from '@wordpress/block-editor';
// drupal import is set as external in webpack.config.js
/* eslint-disable-next-line import/no-unresolved */
import { t } from 'drupal';
import RenderAIResponse from './render';
import parseAIResponse from './parser';
// i18n package could be also used. It is a wrapper around Drupal.t.
// import { __ } from "@wordpress/i18n";
// __('Text to be translated');
const ALLOWED_BLOCKS = ['core/heading', 'core/paragraph', 'core/quote'];
const checkIfHTMLString = (string) => {
const regexForHTML = /<([A-Za-z][A-Za-z0-9]*)\b[^>]*>(.*?)<\/\1>/;
string = JSON.parse(string);
const isValid = regexForHTML.test(string);
if (isValid) {
return true;
}
};
const htmlEntities = (str) => {
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/\n/g, '<br />');
};
function Edit({ attributes, setAttributes }) {
const { title, blockTitle, aiAnswer } = attributes;
const [token, setToken] = useState({ token: '' });
const [isDisabled, setIsDisabled] = useState(false);
const [processingMessage, setProcessingMessage] = useState('');
const [questionCopy, setQuestionCopy] = useState('');
const handleClick = () => {
/* title must not be empty of course */
if (title === undefined) {
setProcessingMessage('Please enter a valid question.');
return false;
}
/* Don't allow the user to click to request AI to answer the same question
* many times, this sends unnecessary requests and consume extra pennies
* that aren't needed */
if (questionCopy === title) {
setProcessingMessage(
'You are asking the same question, please ask another question....',
);
return false;
}
const data = {
ai_prompt: title,
};
setIsDisabled(true);
setProcessingMessage('Processing....');
/* @TODO: these fetch chains look ugly as hell, consider using async/await instead. */
fetch('/session/token')
.then((response) => response.text())
.then((csrfToken) => {
fetch('/gutenberg-ai-tools/ai-rest?_format=json', {
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
'X-Csrf-Token': csrfToken,
},
method: 'POST',
})
.then((response) => response.text())
.then((data) => {
let parsedData = '';
const regex = /\\u([\d\w]{4})/gi;
const found = data.match(regex);
if (found !== null && found.length > 0 && checkIfHTMLString(data)) {
/* eslint-disable-next-line prefer-template */
parsedData = `<code>${htmlEntities(
JSON.parse(data),
)}</code><br /><br />`;
} else {
parsedData = parseAIResponse(data);
}
setToken({ token: parsedData });
setAttributes({ aiAnswer: parsedData });
setIsDisabled(false);
setProcessingMessage('');
setQuestionCopy(title);
})
.catch((error) => console.error(error));
});
};
const postSearch = (value) => {
setAttributes({ aiAnswer: value });
setIsDisabled(false);
setProcessingMessage('');
setQuestionCopy(title);
};
return (
<div {...useBlockProps()}>
<BlockControls></BlockControls>
<InspectorControls>
<PanelBody title={t('Block settings')} initialOpen>
<PanelRow></PanelRow>
<PanelRow>
<TextareaControl
label={t('Block Title')}
help={t(
'Use this field if you want to put a question title above the answer',
)}
value={blockTitle}
onChange={(value) => setAttributes({ blockTitle: value })}
/>
</PanelRow>
<PanelRow>
<TextareaControl
label={t('AI Answer')}
help={t(
'AI answer generated by the engine. You can change the answer here',
)}
value={aiAnswer}
onChange={(value) => postSearch(value)}
/>
</PanelRow>
</PanelBody>
</InspectorControls>
<div>
<RichText
tagName="h2"
placeholder={t('Start typing your question here:')}
value={title}
onChange={(value) => setAttributes({ title: value })}
/>
<button onClick={handleClick} disabled={isDisabled}>
{t('Ask AI')}
</button>
<span> {processingMessage}</span>
<div>
<h3>{blockTitle}</h3>
<RenderAIResponse
question={title}
block_title={blockTitle}
answer={aiAnswer}
/>
<InnerBlocks allowedBlocks={ALLOWED_BLOCKS} />
</div>
</div>
</div>
);
}
export default Edit;
