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 / SocialLinkModal.jsx

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

130 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { track } from '@shared/lib/track';
2 import { Button, Modal, Notice, TextControl } from '@wordpress/components';
3 import { useState } from '@wordpress/element';
4 import { __, sprintf } from '@wordpress/i18n';
5 import { save } from '../../lib/api';
6 import { useCmdEnterSave } from '../../lib/cmd-enter-save';
7 import { friendlyMessage } from '../../lib/errors';
8 import { closeModal, QE_MODAL_BODY_OPEN_CLASS } from '../../lib/modal-root';
9 import { pushUndo } from '../../state/undo';
10 import { ModalCloseButton } from './ModalCloseButton';
11
12 const niceService = (slug) => {
13 if (!slug) return '';
14 return slug.charAt(0).toUpperCase() + slug.slice(1);
15 };
16
17 const readSocialAttrs = (liveEl) => {
18 let service = '';
19 for (const cls of liveEl.classList) {
20 const m = /^wp-social-link-(.+)$/.exec(cls);
21 if (m) {
22 service = m[1];
23 break;
24 }
25 }
26 const a = liveEl.querySelector('a[href]');
27 const url = a?.getAttribute('href') || '';
28 return { service, url };
29 };
30
31 export const SocialLinkModal = ({ selected, onAfterSave }) => {
32 const initial = readSocialAttrs(selected.el);
33 const [url, setUrl] = useState(initial.url);
34 const [saving, setSaving] = useState(false);
35 const [error, setError] = useState(null);
36
37 const handleSave = async () => {
38 if (saving) return;
39 setSaving(true);
40 setError(null);
41 try {
42 // blockId from TagTemplateParts can drift when the template-part
43 // contains a ref-based navigation (the render-time counter
44 // double-counts nav items via render_block's fallback path).
45 // `service` is effectively unique per social-link in a part, so
46 // send it as a fingerprint and let the server fall back to
47 // service-matching when count-based lookup misses.
48 const fingerprint = initial.service ? { service: initial.service } : null;
49 await save({
50 source: selected.source,
51 blockId: selected.blockId,
52 blockType: selected.blockType,
53 fingerprint,
54 patches: [{ fieldKey: 'url', value: url }],
55 });
56 if (url !== initial.url) {
57 pushUndo({
58 kind: 'social-link',
59 source: selected.source,
60 blockId: selected.blockId,
61 blockType: selected.blockType,
62 fingerprint,
63 patches: [{ fieldKey: 'url', value: initial.url }],
64 });
65 }
66 track('save', { kind: 'social_link', service: initial.service });
67 onAfterSave(true);
68 } catch (err) {
69 track('save_failed', { kind: 'social_link', service: initial.service });
70 setError(friendlyMessage(err));
71 setSaving(false);
72 }
73 };
74 useCmdEnterSave(handleSave, !saving);
75
76 const title = initial.service
77 ? sprintf(
78 // translators: %s is the social network name, e.g. "Facebook".
79 __('Edit %s link', 'extendify-local'),
80 niceService(initial.service),
81 )
82 : __('Edit social link', 'extendify-local');
83
84 return (
85 <Modal
86 title={title}
87 onRequestClose={() => onAfterSave(false)}
88 isDismissible={false}
89 headerActions={<ModalCloseButton onClick={() => onAfterSave(false)} />}
90 className="extendify-quick-edit-modal"
91 overlayClassName="extendify-quick-edit"
92 bodyOpenClassName={QE_MODAL_BODY_OPEN_CLASS}
93 size="small"
94 >
95 {error ? (
96 <Notice status="error" isDismissible={false}>
97 {error}
98 </Notice>
99 ) : null}
100 <TextControl
101 __nextHasNoMarginBottom
102 autoFocus
103 label={__('URL', 'extendify-local')}
104 value={url}
105 type="url"
106 placeholder="https://"
107 onChange={setUrl}
108 />
109 <div className="extendify-quick-edit-modal-actions">
110 <Button variant="tertiary" onClick={() => onAfterSave(false)}>
111 {__('Cancel', 'extendify-local')}
112 </Button>
113 <Button
114 variant="primary"
115 isBusy={saving}
116 disabled={saving}
117 onClick={handleSave}
118 >
119 {__('Save', 'extendify-local')}
120 </Button>
121 </div>
122 </Modal>
123 );
124 };
125
126 export const openSocialLinkModal = (selected) => {
127 const handleClose = (didSave) => closeModal(didSave);
128 return <SocialLinkModal selected={selected} onAfterSave={handleClose} />;
129 };
130