PluginProbe
Extendify / 2.2.0
Extendify v2.2.0
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / src / Draft / Draft.jsx

Draft.jsx in Extendify 2.2.0, at src/Draft/Draft.jsx

178 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { store as blockEditorStore } from '@wordpress/block-editor';
2 import { BaseControl, Panel, PanelBody } from '@wordpress/components';
3 import { useSelect } from '@wordpress/data';
4 import { useEffect, useState } from '@wordpress/element';
5 import { __ } from '@wordpress/i18n';
6 import { useAIConsentStore } from '@shared/state/ai-consent';
7 import { Completion } from '@draft/components/Completion';
8 import { ConsentSidebar } from '@draft/components/ConsentSidebar';
9 import { DraftMenu } from '@draft/components/DraftMenu';
10 import { EditMenu } from '@draft/components/EditMenu';
11 import { Input } from '@draft/components/Input';
12 import { InsertMenu } from '@draft/components/InsertMenu';
13 import { SelectedText } from '@draft/components/SelectedText';
14 import { useCompletion } from '@draft/hooks/useCompletion';
15 import { useRouter } from '@draft/hooks/useRouter';
16 import { useSelectedText } from '@draft/hooks/useSelectedText';
17
18 export const Draft = () => {
19 const { selectedText } = useSelectedText();
20 const [inputText, setInputText] = useState('');
21 const [ready, setReady] = useState(false);
22 const [prompt, setPrompt] = useState({
23 text: '',
24 promptType: '',
25 systemMessageKey: '',
26 details: {},
27 });
28 const { completion, loading, error } = useCompletion(
29 prompt.text,
30 prompt.promptType,
31 prompt.systemMessageKey,
32 prompt.details,
33 );
34 const { selectedBlockClientIds, getBlock } = useSelect((select) => {
35 const blockEditor = select(blockEditorStore);
36 return {
37 selectedBlockClientIds: blockEditor.getSelectedBlockClientIds(),
38 getBlock: blockEditor.getBlock,
39 getBlocks: blockEditor.getBlocks,
40 };
41 }, []);
42
43 const { CurrentPage: PhotosSection } = useRouter();
44 // TODO: move to global state
45 const shouldShowAIConsent = useAIConsentStore((state) =>
46 state.shouldShowAIConsent('draft'),
47 );
48
49 // TODO: When doing a rewrite, make this global state
50 useEffect(() => {
51 // Allow for external updates
52 const handle = (event) => {
53 if (shouldShowAIConsent) return;
54 setPrompt(event.detail);
55 };
56 window.addEventListener('extendify-draft:set-prompt', handle);
57 return () =>
58 window.removeEventListener('extendify-draft:set-prompt', handle);
59 }, [shouldShowAIConsent]);
60
61 // Reset input text when an error occurs
62 useEffect(() => {
63 if (!error) return;
64 setInputText(prompt.text);
65 }, [error, prompt.text]);
66
67 const canEditContent = () => {
68 if (selectedBlockClientIds.length === 0) {
69 return false;
70 }
71 const targetBlock = getBlock(selectedBlockClientIds[0]);
72 if (!targetBlock) {
73 return false;
74 }
75 return (
76 typeof targetBlock?.attributes?.content !== 'undefined' &&
77 targetBlock?.attributes?.content !== ''
78 );
79 };
80
81 const isImageBlock = () => {
82 if (selectedBlockClientIds.length === 0) return false;
83
84 const supportedBlocks = [
85 'core/image',
86 'core/media-text',
87 'core/gallery',
88 'core/cover',
89 ];
90 const targetBlock = getBlock(selectedBlockClientIds[0]);
91 if (!targetBlock) return false;
92
93 return supportedBlocks.includes(targetBlock.name);
94 };
95
96 if (shouldShowAIConsent) {
97 return <ConsentSidebar />;
98 }
99
100 if (isImageBlock()) return <PhotosSection />;
101
102 return (
103 <>
104 <Panel>
105 <PanelBody>
106 {selectedText && <SelectedText loading={loading} />}
107
108 <div className="mb-4 overflow-hidden rounded-sm border-none bg-gray-100">
109 {!completion && (
110 <Input
111 inputText={inputText}
112 setInputText={setInputText}
113 ready={ready}
114 setReady={setReady}
115 setPrompt={setPrompt}
116 loading={loading}
117 />
118 )}
119 {completion && <Completion completion={completion} />}
120 {error && (
121 <div className="mb-4 mt-2 px-4">
122 <p className="m-0 text-xs font-semibold text-red-500">
123 {error.message}
124 </p>
125 </div>
126 )}
127 </div>
128 {(completion || loading) && !error && (
129 <InsertMenu
130 prompt={prompt}
131 completion={completion}
132 setPrompt={setPrompt}
133 setInputText={setInputText}
134 loading={loading}
135 />
136 )}
137 {!loading && !completion && canEditContent() && (
138 <BaseControl>
139 <EditMenu
140 completion={completion}
141 disabled={loading}
142 setInputText={setInputText}
143 setPrompt={setPrompt}
144 />
145 </BaseControl>
146 )}
147 {!loading && !completion && !canEditContent() && (
148 <BaseControl label={__('Suggested prompts', 'extendify-local')}>
149 <DraftMenu
150 disabled={loading}
151 setInputText={setInputText}
152 setReady={setReady}
153 />
154 </BaseControl>
155 )}
156 </PanelBody>
157 </Panel>
158 {window.extSharedData?.devbuild && (
159 <Panel>
160 <PanelBody title="Debug" initialOpen={false}>
161 <label>prompt text:</label>
162 <pre className="whitespace-pre-wrap">{prompt.text}</pre>
163 <label>prompt system message:</label>
164 <pre className="whitespace-pre-wrap">{prompt.systemMessageKey}</pre>
165 <label>completion:</label>
166 <pre className="whitespace-pre-wrap">{completion}</pre>
167 <label>error:</label>
168 <pre className="whitespace-pre-wrap">{error?.message ?? ''}</pre>
169 <label>
170 loading: {loading ? <span>true</span> : <span>false</span>}
171 </label>
172 </PanelBody>
173 </Panel>
174 )}
175 </>
176 );
177 };
178