@ai-stack/payloadcms
Version:
<p align="center"> <img alt="Payload AI Plugin" src="assets/payload-ai-intro.gif" width="100%" /> </p>
142 lines (141 loc) • 5.22 kB
JSX
'use client';
import { useEditorConfigContext } from '@payloadcms/richtext-lexical/client';
import { Popup, useDocumentDrawer, useField } from '@payloadcms/ui';
import React, { useCallback, useMemo, useState } from 'react';
import { PLUGIN_INSTRUCTIONS_TABLE } from '../../defaults.js';
import { setSafeLexicalState } from '../../utilities/setSafeLexicalState.js';
import { PluginIcon } from '../Icons/Icons.js';
import styles from './compose.module.css';
import { useMenu } from './hooks/menu/useMenu.js';
import { useActiveFieldTracking } from './hooks/useActiveFieldTracking.js';
import { useGenerate } from './hooks/useGenerate.js';
import { UndoRedoActions } from './UndoRedoActions.js';
export const Compose = ({ descriptionProps, instructionId, isConfigAllowed }) => {
const [DocumentDrawer, _, { closeDrawer, openDrawer }] = useDocumentDrawer({
id: instructionId,
collectionSlug: PLUGIN_INSTRUCTIONS_TABLE,
});
const pathFromContext = descriptionProps?.path;
const { editor: lexicalEditor } = useEditorConfigContext();
// Initialize global active-field tracking
useActiveFieldTracking();
const [isProcessing, setIsProcessing] = useState(false);
const { generate, isLoading, stop } = useGenerate({ instructionId });
const { ActiveComponent, Menu } = useMenu({
onCompose: () => {
console.log('Composing...');
setIsProcessing(true);
generate({
action: 'Compose',
})
.catch((reason) => {
console.error('Compose : ', reason);
})
.finally(() => {
setIsProcessing(false);
});
},
onExpand: () => {
console.log('Expanding...');
generate({
action: 'Expand',
})
.catch((reason) => {
console.error('Compose : ', reason);
})
.finally(() => {
setIsProcessing(false);
});
},
onProofread: () => {
console.log('Proofreading...');
generate({
action: 'Proofread',
})
.catch((reason) => {
console.error('Compose : ', reason);
})
.finally(() => {
setIsProcessing(false);
});
},
onRephrase: () => {
console.log('Rephrasing...');
generate({
action: 'Rephrase',
})
.catch((reason) => {
console.error('Compose : ', reason);
})
.finally(() => {
setIsProcessing(false);
});
},
onSettings: isConfigAllowed ? openDrawer : undefined,
onSimplify: () => {
console.log('Simplifying...');
generate({
action: 'Simplify',
})
.catch((reason) => {
console.error('Compose : ', reason);
})
.finally(() => {
setIsProcessing(false);
});
},
onSummarize: () => {
console.log('Summarizing...');
generate({
action: 'Summarize',
})
.catch((reason) => {
console.error('Compose : ', reason);
})
.finally(() => {
setIsProcessing(false);
});
},
onTranslate: (data) => {
console.log('Translating...');
generate({
action: 'Translate',
params: data,
})
.catch((reason) => {
console.error('Compose : ', reason);
})
.finally(() => {
setIsProcessing(false);
});
},
}, {
isConfigAllowed,
});
const { setValue } = useField({
path: pathFromContext,
});
const setIfValueIsLexicalState = useCallback((val) => {
if (val && typeof val === 'object' && 'root' in val && lexicalEditor) {
setSafeLexicalState(JSON.stringify(val), lexicalEditor);
}
// DO NOT PROVIDE lexicalEditor as a dependency, it freaks out and does not update the editor after first undo/redo
}, []);
const popupRender = useCallback(({ close }) => {
return <Menu isLoading={isProcessing || isLoading} onClose={close}/>;
}, [isProcessing, isLoading, Menu]);
const memoizedPopup = useMemo(() => {
return (<Popup button={<PluginIcon isLoading={isProcessing || isLoading}/>} render={popupRender} verticalAlign="bottom"/>);
}, [popupRender, isProcessing, isLoading]);
return (<label className={`payloadai-compose__actions ${styles.actions}`} onClick={(e) => e.preventDefault()} role="presentation">
<DocumentDrawer onSave={() => {
closeDrawer();
}}/>
{memoizedPopup}
<ActiveComponent isLoading={isProcessing || isLoading} stop={stop}/>
<UndoRedoActions onChange={(val) => {
setValue(val);
setIfValueIsLexicalState(val);
}}/>
</label>);
};