PluginProbe
Extendify / 2.2.0
Extendify v2.2.0
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 / Assist / components / ImageUploader.jsx

ImageUploader.jsx in Extendify 2.2.0, at src/Assist/components/ImageUploader.jsx

186 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import apiFetch from '@wordpress/api-fetch';
2 import { isBlobURL } from '@wordpress/blob';
3 import {
4 DropZone,
5 Button,
6 Spinner,
7 ResponsiveWrapper,
8 } from '@wordpress/components';
9 import { store as coreStore } from '@wordpress/core-data';
10 import { useSelect } from '@wordpress/data';
11 import { useEffect } from '@wordpress/element';
12 import { useState } from '@wordpress/element';
13 import { __ } from '@wordpress/i18n';
14 import { MediaUpload, uploadMedia } from '@wordpress/media-utils';
15 import { getMediaDetails } from '@assist/lib/media';
16 import { useGlobalStore } from '@assist/state/globals';
17
18 export const ImageUploader = ({ type, onUpdate, title, actionLabel }) => {
19 const { popModal } = useGlobalStore();
20 const [isLoading, setIsLoading] = useState(false);
21 const [imageId, setImageId] = useState(0);
22 const media = useSelect(
23 (select) => select(coreStore).getMedia(imageId),
24 [imageId],
25 );
26 const { mediaWidth, mediaHeight, mediaSourceUrl } = getMediaDetails(media);
27
28 useEffect(() => {
29 const controller = new AbortController();
30
31 apiFetch({
32 path: '/wp/v2/settings',
33 signal: controller.signal,
34 }).then((settings) => {
35 if (settings[type]) setImageId(Number(settings[type]));
36 });
37
38 return () => controller.abort();
39 }, [type]);
40
41 const updateOption = async (type, id) => {
42 await apiFetch({
43 path: '/wp/v2/settings',
44 method: 'post',
45 data: { [type]: id },
46 });
47 };
48
49 const onUpdateImage = async (image) => {
50 setImageId(image.id);
51 await updateOption(type, image.id);
52 onUpdate();
53 };
54 const onRemoveImage = async () => {
55 setImageId(0);
56 await updateOption(type, 0);
57 };
58
59 const onDropFiles = (filesList) => {
60 uploadMedia({
61 allowedTypes: ['image'],
62 filesList,
63 onFileChange([image]) {
64 if (isBlobURL(image?.url)) {
65 setIsLoading(true);
66 return;
67 }
68 onUpdateImage(image);
69 setIsLoading(false);
70 },
71 onError(message) {
72 console.error({ message });
73 },
74 });
75 };
76
77 return (
78 <div>
79 <MediaUploadCheck>
80 <MediaUpload
81 title={title}
82 onSelect={onUpdateImage}
83 allowedTypes={['image']}
84 value={imageId}
85 modalClass=""
86 render={({ open }) => (
87 <div className="relative block">
88 <Button
89 className={
90 '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'
91 }
92 onClick={open}
93 aria-label={
94 !imageId
95 ? null
96 : __('Edit or update the image', 'extendify-local')
97 }
98 aria-describedby={
99 !imageId ? null : `image-${imageId}-describedby`
100 }>
101 {Boolean(imageId) && media && (
102 <>
103 <ResponsiveWrapper
104 naturalWidth={mediaWidth}
105 naturalHeight={mediaHeight}
106 isInline>
107 <img
108 className="inset-0 m-auto block h-auto max-h-48 w-auto max-w-96"
109 src={mediaSourceUrl}
110 alt=""
111 />
112 </ResponsiveWrapper>
113 </>
114 )}
115 {isLoading && <Spinner />}
116 {!imageId && !isLoading && actionLabel}
117 </Button>
118 <DropZone
119 className="absolute inset-0 h-full w-full"
120 onFilesDrop={onDropFiles}
121 />
122 </div>
123 )}
124 />
125 </MediaUploadCheck>
126 {Boolean(imageId) && (
127 <div className="mt-6 flex justify-between gap-4">
128 <MediaUploadCheck>
129 <div>
130 {imageId && (
131 <MediaUpload
132 title={title}
133 onSelect={onUpdateImage}
134 unstableFeaturedImageFlow
135 allowedTypes={['image']}
136 modalClass="image__media-modal"
137 render={({ open }) => (
138 <Button onClick={open} variant="secondary">
139 {__('Replace image', 'extendify-local')}
140 </Button>
141 )}
142 />
143 )}
144 <Button
145 onClick={onRemoveImage}
146 variant="link"
147 className="ml-4"
148 isDestructive>
149 {__('Remove image', 'extendify-local')}
150 </Button>
151 </div>
152 <div>
153 <Button
154 variant="primary"
155 onClick={popModal}
156 className="bg-design-main text-design-text">
157 {__('Done', 'extendify-local')}
158 </Button>
159 </div>
160 </MediaUploadCheck>
161 </div>
162 )}
163 </div>
164 );
165 };
166
167 const MediaUploadCheck = ({ fallback = null, children }) => {
168 const { checkingPermissions, hasUploadPermissions } = useSelect((select) => {
169 const core = select('core');
170 return {
171 hasUploadPermissions: core.canUser('read', 'media'),
172 checkingPermissions: !core.hasFinishedResolution('canUser', [
173 'read',
174 'media',
175 ]),
176 };
177 });
178
179 return (
180 <>
181 {checkingPermissions && <Spinner />}
182 {!checkingPermissions && hasUploadPermissions ? children : fallback}
183 </>
184 );
185 };
186