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 / QuickEdit / components / modals / SiteIdentityModal.jsx

SiteIdentityModal.jsx in Extendify 3.2.1, at src/QuickEdit/components/modals/SiteIdentityModal.jsx

196 lines 5.4 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 '@shared/lib/media-views';
5 import { track } from '@shared/lib/track';
6 import { MediaUpload } from '@wordpress/block-editor';
7 import {
8 Button,
9 Modal,
10 Notice,
11 Spinner,
12 TextControl,
13 } from '@wordpress/components';
14 import { useEffect, useState } from '@wordpress/element';
15 import { __ } from '@wordpress/i18n';
16 import { loadSiteIdentity, saveSiteIdentity } from '../../lib/api';
17 import { useCmdEnterSave } from '../../lib/cmd-enter-save';
18 import { friendlyMessage } from '../../lib/errors';
19 import { closeModal, QE_MODAL_BODY_OPEN_CLASS } from '../../lib/modal-root';
20 import { pushUndo } from '../../state/undo';
21 import { ModalCloseButton } from './ModalCloseButton';
22
23 const TITLES = {
24 title: __('Site title', 'extendify-local'),
25 tagline: __('Tagline', 'extendify-local'),
26 logo: __('Site logo', 'extendify-local'),
27 };
28
29 export const SiteIdentityModal = ({ kind, onAfterSave }) => {
30 const [data, setData] = useState(null);
31 // Static snapshot for the undo before-state.
32 const [originalData, setOriginalData] = useState(null);
33 const [saving, setSaving] = useState(false);
34 const [error, setError] = useState(null);
35
36 useEffect(() => {
37 loadSiteIdentity()
38 .then((res) => {
39 setData(res);
40 setOriginalData(res);
41 })
42 .catch((err) => setError(friendlyMessage(err)));
43 }, []);
44
45 // Logo is the only kind that opens wp.media (via MediaUpload). Armor its
46 // chrome against the site theme's CSS bleed — same fix as InlineEditor's
47 // image picker. See @shared/lib/media-views.
48 useEffect(() => {
49 if (kind !== 'logo') return undefined;
50 addCustomMediaViewsCss();
51 return () => removeCustomMediaViewsCss();
52 }, [kind]);
53
54 const handleSave = async () => {
55 if (saving || !data) return;
56 setSaving(true);
57 setError(null);
58 const payload = {};
59 const beforeValues = {};
60 if (kind === 'title') {
61 payload.title = data.title;
62 beforeValues.title = originalData ? originalData.title : '';
63 }
64 if (kind === 'tagline') {
65 payload.tagline = data.tagline;
66 beforeValues.tagline = originalData ? originalData.tagline : '';
67 }
68 if (kind === 'logo') {
69 payload.logo_id = data.logo_id;
70 beforeValues.logo_id = originalData ? originalData.logo_id : 0;
71 }
72 if (
73 originalData &&
74 JSON.stringify(beforeValues) === JSON.stringify(payload)
75 ) {
76 onAfterSave(false);
77 return;
78 }
79 try {
80 await saveSiteIdentity(payload);
81 pushUndo({
82 kind: 'site-identity',
83 identityKind: kind,
84 beforeValues,
85 // Routes performUndo through saveSiteIdentity instead of SaveController.
86 identityReplay: true,
87 });
88 track('save', { kind: 'site_identity', field: kind });
89 onAfterSave(true);
90 } catch (err) {
91 track('save_failed', { kind: 'site_identity', field: kind });
92 setError(friendlyMessage(err));
93 setSaving(false);
94 }
95 };
96 useCmdEnterSave(handleSave, !!data && !saving);
97
98 return (
99 <Modal
100 title={TITLES[kind] || __('Site identity', 'extendify-local')}
101 onRequestClose={() => onAfterSave(false)}
102 isDismissible={false}
103 headerActions={<ModalCloseButton onClick={() => onAfterSave(false)} />}
104 className="extendify-quick-edit-modal"
105 overlayClassName="extendify-quick-edit"
106 bodyOpenClassName={QE_MODAL_BODY_OPEN_CLASS}
107 size="medium"
108 >
109 {error ? (
110 <Notice status="error" isDismissible={false}>
111 {error}
112 </Notice>
113 ) : null}
114 {!data && !error ? <Spinner /> : null}
115 {data && kind === 'title' ? (
116 <TextControl
117 __nextHasNoMarginBottom
118 autoFocus
119 label={__('Site title', 'extendify-local')}
120 value={data.title || ''}
121 onChange={(v) => setData({ ...data, title: v })}
122 />
123 ) : null}
124 {data && kind === 'tagline' ? (
125 <TextControl
126 __nextHasNoMarginBottom
127 autoFocus
128 label={__('Tagline', 'extendify-local')}
129 value={data.tagline || ''}
130 onChange={(v) => setData({ ...data, tagline: v })}
131 />
132 ) : null}
133 {data && kind === 'logo' ? (
134 <div className="extendify-quick-edit-logo-row">
135 {data.logo_url ? (
136 <img
137 src={data.logo_url}
138 alt=""
139 className="extendify-quick-edit-logo-preview"
140 />
141 ) : null}
142 <MediaUpload
143 onSelect={(m) =>
144 setData({
145 ...data,
146 logo_id: m.id,
147 logo_url: m.sizes?.medium ? m.sizes.medium.url : m.url,
148 })
149 }
150 allowedTypes={['image']}
151 value={data.logo_id}
152 render={({ open }) => (
153 <div className="extendify-quick-edit-logo-buttons">
154 <Button variant="secondary" onClick={open}>
155 {data.logo_id
156 ? __('Change logo', 'extendify-local')
157 : __('Choose logo', 'extendify-local')}
158 </Button>
159 {data.logo_id ? (
160 <Button
161 variant="tertiary"
162 isDestructive
163 onClick={() =>
164 setData({ ...data, logo_id: 0, logo_url: '' })
165 }
166 >
167 {__('Remove', 'extendify-local')}
168 </Button>
169 ) : null}
170 </div>
171 )}
172 />
173 </div>
174 ) : null}
175 <div className="extendify-quick-edit-modal-actions">
176 <Button variant="tertiary" onClick={() => onAfterSave(false)}>
177 {__('Cancel', 'extendify-local')}
178 </Button>
179 <Button
180 variant="primary"
181 isBusy={saving}
182 disabled={saving || !data}
183 onClick={handleSave}
184 >
185 {__('Save', 'extendify-local')}
186 </Button>
187 </div>
188 </Modal>
189 );
190 };
191
192 export const openSiteIdentityModal = (kind) => {
193 const handleClose = (didSave) => closeModal(didSave);
194 return <SiteIdentityModal kind={kind} onAfterSave={handleClose} />;
195 };
196