PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 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 All 127 releases
extendify / src / Draft / pages / GenerateImage.jsx

GenerateImage.jsx in Extendify 3.2.1, at src/Draft/pages/GenerateImage.jsx

138 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { GenerateForm } from '@draft/components/image-generation/GenerateForm';
2 import { ImagePreview } from '@draft/components/image-generation/ImagePreview';
3 import { useRouter } from '@draft/hooks/useRouter';
4 import { pageState } from '@draft/state/factory';
5 import { backArrow } from '@draft/svg/BackArrow';
6 import { generateImage } from '@shared/api/DataApi';
7 import { useImageGenerationStore } from '@shared/state/generate-images';
8 import {
9 BaseControl,
10 __experimentalHeading as Heading,
11 Panel,
12 PanelBody,
13 } from '@wordpress/components';
14 import { useEffect, useRef, useState } from '@wordpress/element';
15 import { __ } from '@wordpress/i18n';
16
17 const usePageState = pageState('AI Image', (set) => ({
18 imageDetails: { src: '', id: undefined },
19 setImageDetails: (newState) => {
20 set((state) => ({ ...state, imageDetails: newState }));
21 },
22 }));
23
24 export const GenerateImage = () => {
25 const {
26 imageCredits: curCredits,
27 updateImageCredits,
28 subtractOneCredit,
29 aiImageOptions,
30 } = useImageGenerationStore();
31 const [isGenerating, setIsGenerating] = useState(false);
32 const [disclose, setDisclose] = useState(false);
33 const [errorMessage, setErrorMessage] = useState('');
34 const abortController = useRef(null);
35 const noCredits = curCredits.remaining === 0;
36 const { imageDetails, setImageDetails } = usePageState();
37 const { goBack } = useRouter();
38
39 const clearImageResponse = () => setImageDetails({ src: '', id: undefined });
40 const handleSubmit = async (event) => {
41 event.preventDefault();
42 setErrorMessage('');
43 if (noCredits) {
44 abortController.current?.abort();
45 return;
46 }
47
48 try {
49 setIsGenerating(true);
50 subtractOneCredit();
51 abortController.current = new AbortController();
52 const { imageCredits, images, id } = await generateImage(
53 { ...aiImageOptions, source: 'draft' },
54 abortController.current.signal,
55 );
56 updateImageCredits(imageCredits);
57 setImageDetails({
58 src: images[0].url,
59 id,
60 alt: images[0].alt ?? aiImageOptions.prompt,
61 });
62 } catch (error) {
63 // If the request was aborted (canceled), don't show an error
64 if (error?.code === 20) return;
65 // If we didn't get back any credit info, it was a server error
66 if (!error?.imageCredits) {
67 // Pause to prevent flickering
68 await new Promise((resolve) => setTimeout(resolve, 1000));
69 setErrorMessage(error.message);
70 // Add back the credit we subtracted
71 updateImageCredits({ remaining: curCredits.remaining });
72 return;
73 }
74 // Probably out of credits here
75 updateImageCredits(error.imageCredits);
76 setErrorMessage(error.message);
77 } finally {
78 setIsGenerating(false);
79 }
80 };
81
82 useEffect(() => {
83 if (imageDetails.src || isGenerating) return;
84 // refocus when image is removed
85 document.getElementById('draft-ai-image-textarea')?.focus();
86 }, [imageDetails.src, isGenerating]);
87
88 return (
89 <Panel>
90 <div className="flex h-12 items-center gap-1 pl-1">
91 <button
92 className="h-9 w-9 border-0 bg-transparent"
93 onClick={goBack}
94 type="button"
95 aria-label={__('Go Back', 'extendify-local')}
96 >
97 {backArrow}
98 </button>
99 <Heading className="mb-0">
100 {__('AI Image Generator', 'extendify-local')}
101 </Heading>
102 </div>
103 <PanelBody className="-mt-4 border-t-0">
104 <BaseControl label={__('Image Description', 'extendify-local')}>
105 <ImagePreview
106 prompt={aiImageOptions.prompt}
107 alt={imageDetails?.alt}
108 size={aiImageOptions.size}
109 isGenerating={isGenerating}
110 id={imageDetails?.id}
111 src={imageDetails?.src}
112 disclose={disclose}
113 clearImageResponse={clearImageResponse}
114 />
115 {imageDetails.src ? null : (
116 <form onSubmit={handleSubmit} className="flex flex-col gap-5">
117 <GenerateForm
118 isGenerating={isGenerating}
119 errorMessage={errorMessage}
120 disclose={disclose}
121 setDisclose={setDisclose}
122 />
123 </form>
124 )}
125 </BaseControl>
126 </PanelBody>
127 </Panel>
128 );
129 };
130
131 export const routes = [
132 {
133 slug: 'ai-image',
134 title: __('AI Image', 'extendify-local'),
135 component: GenerateImage,
136 },
137 ];
138