import { DropdownMenu } from '@/components/dropdownMenu'; import { useSettings } from '@/settings'; import { ai, hideLoadingMessage, showLoadingMessage, showNotice } from '@/utils'; import { useService } from '@/utils/ai/services/useService'; import { Button, Flex, Modal, TextareaControl } from '@wordpress/components'; import { useCallback, useEffect, useMemo, useRef, useState } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import _ from 'underscore'; type Props = { id: string; }; const getElement = (id: string) => document.getElementById(id) as HTMLTextAreaElement; const useControl = ({ id }: Props) => { const textareaRef = useRef(null); const [hasValue, setHasValue] = useState(!!getElement(id)?.value); const [showModal, setShowModal] = useState(false); const { settings } = useSettings(); const descriptionPromptService = useService('wc_product_description_prompt_service'); const excerptPromptService = useService('wc_product_excerpt_prompt_service'); const data = useMemo(() => { switch (id) { case 'excerpt': return { enabled: settings?.wc_product_excerpt_enabled, promptPrefix: settings?.wc_product_excerpt_prompt, service: excerptPromptService, loadingMessage: __('Short Description', 'filter-ai'), successMessage: __('Product short description has been updated', 'filter-ai'), serviceSuccessMessage: sprintf( __('Product short description has been updated using %s', 'filter-ai'), excerptPromptService?.metadata.name || '' ), errorMessage: __( 'Sorry, there has been an issue while generating your product short description.', 'filter-ai' ), generateLabel: __('Generate short description', 'filter-ai'), regenerateLabel: __('Regenerate short description', 'filter-ai'), }; default: return { enabled: settings?.wc_product_description_enabled, promptPrefix: settings?.wc_product_description_prompt, service: descriptionPromptService, loadingMessage: __('Description', 'filter-ai'), successMessage: __('Product description has been updated', 'filter-ai'), serviceSuccessMessage: sprintf( __('Product description has been updated using %s', 'filter-ai'), descriptionPromptService?.metadata.name || '' ), errorMessage: __('Sorry, there has been an issue while generating your product description.', 'filter-ai'), generateLabel: __('Generate description', 'filter-ai'), regenerateLabel: __('Regenerate description', 'filter-ai'), }; } }, [id, settings, descriptionPromptService, excerptPromptService]); const updateValue = (newValue: string) => { const content = getElement(id); if (!content) { return; } content.value = newValue; content.dispatchEvent(new Event('change')); window.tinymce?.get(id)?.setContent(newValue); }; const generate = async (promptSuffix?: string) => { if (!promptSuffix) { return; } showLoadingMessage(data.loadingMessage); try { const prompt = `${data.promptPrefix} ${promptSuffix}`; const content = await ai.generateText({ feature: `filter-ai-wc-product-${id}`, prompt, service: data.service?.slug, }); if (!content) { throw new Error(data.errorMessage); } updateValue(content); let message; if (data.service?.metadata.name) { message = data.serviceSuccessMessage; } else { message = data.successMessage; } showNotice({ message }); } catch (error) { console.error(error); // @ts-expect-error Property 'message' does not exist on type '{}' showNotice({ message: error?.message || error, type: 'error' }); } finally { hideLoadingMessage(); } }; const onClick = async () => { let value = ''; switch (id) { case 'excerpt': value = getElement(id)?.value || getElement('content')?.value; break; default: getElement(id)?.value; } if (value) { generate(value); } else { setShowModal(true); } }; const checkHasValue = () => { setHasValue(!!getElement(id)?.value); }; const ControlModal = useCallback(() => { if (!showModal) { return null; } return ( { setShowModal(false); }} size="medium" >
{__('Please provide information about the product to generate a description:', 'filter-ai')}
{/* @ts-expect-error */} {}} __nextHasNoMarginBottom />
); }, [showModal]); useEffect(() => { const abortController = new AbortController(); getElement(id)?.addEventListener('input', checkHasValue, { signal: abortController.signal, }); getElement(id)?.addEventListener('change', checkHasValue, { signal: abortController.signal, }); return () => { abortController.abort(); }; }, []); if (!data.enabled) { return { ControlModal: () => null, control: null, }; } return { ControlModal, control: { title: hasValue ? data.regenerateLabel : data.generateLabel, onClick, }, }; }; export const ProductToolbar = (props: Props) => { const { ControlModal, control } = useControl(props); const controls = _.compact([control]); return ( <> ); };