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 / Assist / components / ImageUploader.jsx

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

188 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { getMediaDetails } from '@assist/lib/media';
2 import { useGlobalStore } from '@assist/state/globals';
3 import apiFetch from '@wordpress/api-fetch';
4 import { isBlobURL } from '@wordpress/blob';
5 import {
6 Button,
7 DropZone,
8 ResponsiveWrapper,
9 Spinner,
10 } from '@wordpress/components';
11 import { store as coreStore } from '@wordpress/core-data';
12 import { useSelect } from '@wordpress/data';
13 import { useEffect, useState } from '@wordpress/element';
14 import { __ } from '@wordpress/i18n';
15 import { MediaUpload, uploadMedia } from '@wordpress/media-utils';
16
17 export const ImageUploader = ({ type, onUpdate, title, actionLabel }) => {
18 const { popModal } = useGlobalStore();
19 const [isLoading, setIsLoading] = useState(false);
20 const [imageId, setImageId] = useState(0);
21 const media = useSelect(
22 (select) =>
23 select(coreStore).getEntityRecord('postType', 'attachment', 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 >
102 {Boolean(imageId) && media && (
103 <ResponsiveWrapper
104 naturalWidth={mediaWidth}
105 naturalHeight={mediaHeight}
106 isInline
107 >
108 <img
109 className="inset-0 m-auto block h-auto max-h-48 w-auto max-w-96"
110 src={mediaSourceUrl}
111 alt=""
112 />
113 </ResponsiveWrapper>
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 >
150 {__('Remove image', 'extendify-local')}
151 </Button>
152 </div>
153 <div>
154 <Button
155 variant="primary"
156 onClick={popModal}
157 className="bg-design-main text-design-text"
158 >
159 {__('Done', 'extendify-local')}
160 </Button>
161 </div>
162 </MediaUploadCheck>
163 </div>
164 )}
165 </div>
166 );
167 };
168
169 const MediaUploadCheck = ({ fallback = null, children }) => {
170 const { checkingPermissions, hasUploadPermissions } = useSelect((select) => {
171 const core = select('core');
172 return {
173 hasUploadPermissions: core.canUser('read', 'media'),
174 checkingPermissions: !core.hasFinishedResolution('canUser', [
175 'read',
176 'media',
177 ]),
178 };
179 });
180
181 return (
182 <>
183 {checkingPermissions && <Spinner />}
184 {!checkingPermissions && hasUploadPermissions ? children : fallback}
185 </>
186 );
187 };
188