PluginProbe
Extendify / 3.0.4
Extendify v3.0.4
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 / Agent / components / ImageUploader.jsx

ImageUploader.jsx in Extendify 3.0.4, at src/Agent/components/ImageUploader.jsx

255 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {
2 addCustomMediaViewsCss,
3 removeCustomMediaViewsCss,
4 } from '@agent/lib/media-views';
5 import { getMediaDetails } from '@assist/lib/media';
6 import apiFetch from '@wordpress/api-fetch';
7 import { isBlobURL } from '@wordpress/blob';
8 import {
9 Button,
10 DropZone,
11 ResponsiveWrapper,
12 Spinner,
13 } from '@wordpress/components';
14 import { store as coreStore } from '@wordpress/core-data';
15 import { useSelect } from '@wordpress/data';
16 import { useEffect, useState } from '@wordpress/element';
17 import { __ } from '@wordpress/i18n';
18 import { MediaUpload, uploadMedia } from '@wordpress/media-utils';
19 import classnames from 'classnames';
20
21 const allowedTypes = ['image'];
22
23 const getSettings = (signal) => {
24 return apiFetch({
25 path: '/wp/v2/settings',
26 signal,
27 });
28 };
29
30 export const ImageUploader = ({
31 type,
32 onSave,
33 onCancel,
34 onSelect,
35 title,
36 actionLabel,
37 }) => {
38 const [isLoading, setIsLoading] = useState(false);
39 const [isSaving, setIsSaving] = useState(false);
40 const [savedImageId, setSavedImageId] = useState(null);
41 const [selectedImageId, setSelectedImageId] = useState(null);
42
43 const imageId = selectedImageId || savedImageId;
44
45 const media = useSelect(
46 (select) => {
47 return select(coreStore).getEntityRecord(
48 'postType',
49 'attachment',
50 imageId,
51 );
52 },
53 [imageId],
54 );
55 const { mediaWidth, mediaHeight, mediaSourceUrl } = getMediaDetails(media);
56
57 useEffect(() => {
58 addCustomMediaViewsCss();
59
60 return () => removeCustomMediaViewsCss();
61 }, []);
62
63 useEffect(() => {
64 const controller = new AbortController();
65
66 setIsLoading(true);
67
68 getSettings(controller.signal)
69 .then((settings) => {
70 if (settings[type]) setSavedImageId(Number(settings[type]));
71 })
72 .finally(() => setIsLoading(false));
73
74 return () => controller.abort();
75 }, [type]);
76
77 const handleOnSelectImage = (image) => {
78 if (image.id === imageId) {
79 return;
80 }
81
82 setSelectedImageId(image.id);
83 onSelect?.(image);
84 };
85
86 const onRemoveImage = () => {
87 setSelectedImageId(null);
88 setSavedImageId(null);
89 onCancel();
90 };
91
92 const handleOnSave = async () => {
93 setIsSaving(true);
94
95 try {
96 await onSave?.({ imageId: selectedImageId });
97 } catch (error) {
98 console.error(error);
99 } finally {
100 setIsSaving(false);
101 }
102 };
103
104 const onDropFiles = (filesList) => {
105 uploadMedia({
106 allowedTypes,
107 filesList,
108 onFileChange([image]) {
109 if (isBlobURL(image?.url)) {
110 setIsLoading(true);
111 return;
112 }
113 handleOnSelectImage(image);
114 setIsLoading(false);
115 },
116 onError(message) {
117 console.error({ message });
118 },
119 });
120 };
121
122 return (
123 <div className="extendify-shared">
124 <MediaUploadCheck>
125 <MediaUpload
126 title={title}
127 onSelect={handleOnSelectImage}
128 allowedTypes={allowedTypes}
129 value={imageId}
130 modalClass=""
131 render={({ open }) => (
132 <div className="relative block">
133 <Button
134 className={
135 'editor-post-featured-image__toggle extendify-assist-upload-logo relative m-0 flex h-48 w-full min-w-full justify-center border-0 bg-gray-100 p-0 text-center text-gray-900 hover:bg-gray-300 hover:text-current'
136 }
137 onClick={open}
138 aria-label={
139 !imageId
140 ? null
141 : __('Edit or update the image', 'extendify-local')
142 }
143 aria-describedby={
144 !imageId ? null : `image-${imageId}-describedby`
145 }
146 >
147 {imageId && media && !isLoading && (
148 <ResponsiveWrapper
149 naturalWidth={mediaWidth}
150 naturalHeight={mediaHeight}
151 isInline
152 >
153 <img
154 className="inset-0 m-auto block h-auto max-h-48 w-auto max-w-96"
155 src={mediaSourceUrl}
156 alt=""
157 />
158 </ResponsiveWrapper>
159 )}
160 {isLoading && <Spinner />}
161 {!imageId &&
162 !isLoading &&
163 (actionLabel || (
164 <div className="flex flex-col">{actionLabel}</div>
165 ))}
166 </Button>
167 <DropZone
168 className="absolute inset-0 h-full w-full"
169 onFilesDrop={onDropFiles}
170 label={__('Drop images to upload', 'extendify-local')}
171 />
172 </div>
173 )}
174 />
175
176 <div className="mt-6">
177 <div className="flex gap-2">
178 <button
179 type="button"
180 onClick={onRemoveImage}
181 className={classnames(
182 'w-full rounded-sm border border-gray-300 bg-white p-2 text-sm text-gray-800 hover:bg-gray-50',
183 {
184 'cursor-not-allowed': isSaving,
185 },
186 )}
187 disabled={isSaving}
188 >
189 {__('Cancel', 'extendify-local')}
190 </button>
191
192 {!selectedImageId && (
193 <MediaUpload
194 title={title}
195 onSelect={handleOnSelectImage}
196 allowedTypes={allowedTypes}
197 modalClass="image__media-modal"
198 render={({ open }) => (
199 <button
200 type="button"
201 onClick={open}
202 className="w-full rounded-sm border border-design-main bg-design-main p-2 text-sm text-white hover:bg-gray-800"
203 >
204 {__('Open Media Library', 'extendify-local')}
205 </button>
206 )}
207 />
208 )}
209
210 {selectedImageId && (
211 <button
212 type="button"
213 onClick={handleOnSave}
214 className={classnames(
215 'flex items-center justify-center w-full rounded-sm border border-design-main bg-design-main p-2 text-sm text-white hover:bg-gray-800',
216 {
217 'cursor-not-allowed': isSaving,
218 },
219 )}
220 disabled={isSaving}
221 >
222 {isSaving ? (
223 <Spinner className="m-0" />
224 ) : (
225 __('Save', 'extendify-local')
226 )}
227 </button>
228 )}
229 </div>
230 </div>
231 </MediaUploadCheck>
232 </div>
233 );
234 };
235
236 const MediaUploadCheck = ({ fallback = null, children }) => {
237 const { checkingPermissions, hasUploadPermissions } = useSelect((select) => {
238 const core = select('core');
239 return {
240 hasUploadPermissions: core.canUser('read', 'media'),
241 checkingPermissions: !core.hasFinishedResolution('canUser', [
242 'read',
243 'media',
244 ]),
245 };
246 });
247
248 return (
249 <>
250 {checkingPermissions && <Spinner />}
251 {!checkingPermissions && hasUploadPermissions ? children : fallback}
252 </>
253 );
254 };
255