PluginProbe
Extendify / 3.1.0
Extendify v3.1.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 / QuickEdit / components / modals / ProductTextModal.jsx

ProductTextModal.jsx in Extendify 3.1.0, at src/QuickEdit/components/modals/ProductTextModal.jsx

143 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {
2 Button,
3 Modal,
4 Notice,
5 Spinner,
6 TextareaControl,
7 TextControl,
8 } from '@wordpress/components';
9 import { useEffect, useState } from '@wordpress/element';
10 import { __ } from '@wordpress/i18n';
11 import { loadProduct, saveProduct } from '../../lib/api';
12 import { useCmdEnterSave } from '../../lib/cmd-enter-save';
13 import { friendlyMessage } from '../../lib/errors';
14 import { track } from '../../lib/insights';
15 import { QE_MODAL_BODY_OPEN_CLASS } from '../../lib/modal-root';
16 import { pushUndo } from '../../state/undo';
17 import { ModalCloseButton } from './ModalCloseButton';
18
19 const TITLES = {
20 name: __('Edit product name', 'extendify-local'),
21 short_description: __('Edit short description', 'extendify-local'),
22 description: __('Edit description', 'extendify-local'),
23 };
24
25 export const ProductTextModal = ({ productId, field, onAfterSave }) => {
26 const [data, setData] = useState(null);
27 const [originalValue, setOriginalValue] = useState('');
28 const [value, setValue] = useState('');
29 const [saving, setSaving] = useState(false);
30 const [error, setError] = useState(null);
31
32 useEffect(() => {
33 loadProduct(productId)
34 .then((res) => {
35 setData(res);
36 let v = res[field] || '';
37 // When the product has no short description but the page is
38 // showing the long-description fallback above the price (WC's
39 // `woocommerce/product-summary` block does this via
40 // `showDescriptionIfEmpty`), the modal would open empty even
41 // though the user sees text. Pre-fill with the long description
42 // so editing matches what's displayed; save still writes to
43 // post_excerpt — once saved the product has a real short
44 // description and future opens show it directly.
45 if (field === 'short_description' && !v && res.description) {
46 v = res.description;
47 }
48 setOriginalValue(v);
49 setValue(v);
50 })
51 .catch((err) => setError(friendlyMessage(err)));
52 }, [productId, field]);
53
54 const handleSave = async () => {
55 if (saving || !data) return;
56 if (value === originalValue) {
57 onAfterSave(false);
58 return;
59 }
60 setSaving(true);
61 setError(null);
62 try {
63 await saveProduct({ productId, field, value });
64 pushUndo({
65 kind: 'product',
66 productReplay: true,
67 productId,
68 field,
69 beforeValue: originalValue,
70 });
71 track('save', { kind: 'product', field });
72 onAfterSave(true);
73 } catch (err) {
74 track('save_failed', { kind: 'product', field });
75 setError(friendlyMessage(err));
76 setSaving(false);
77 }
78 };
79 useCmdEnterSave(handleSave, !!data && !saving);
80
81 return (
82 <Modal
83 title={TITLES[field] || __('Edit product field', 'extendify-local')}
84 onRequestClose={() => onAfterSave(false)}
85 isDismissible={false}
86 headerActions={<ModalCloseButton onClick={() => onAfterSave(false)} />}
87 className="extendify-quick-edit-modal"
88 overlayClassName="extendify-quick-edit"
89 bodyOpenClassName={QE_MODAL_BODY_OPEN_CLASS}
90 size="medium"
91 >
92 {error ? (
93 <Notice status="error" isDismissible={false}>
94 {error}
95 </Notice>
96 ) : null}
97 {!data && !error ? <Spinner /> : null}
98 {data && field === 'name' ? (
99 <TextControl
100 __nextHasNoMarginBottom
101 label={__('Product name', 'extendify-local')}
102 value={value}
103 onChange={setValue}
104 autoFocus
105 />
106 ) : null}
107 {data && field === 'short_description' ? (
108 <TextareaControl
109 __nextHasNoMarginBottom
110 label={__('Short description', 'extendify-local')}
111 value={value}
112 onChange={setValue}
113 rows={6}
114 autoFocus
115 />
116 ) : null}
117 {data && field === 'description' ? (
118 <TextareaControl
119 __nextHasNoMarginBottom
120 label={__('Description', 'extendify-local')}
121 value={value}
122 onChange={setValue}
123 rows={14}
124 autoFocus
125 />
126 ) : null}
127 <div className="extendify-quick-edit-modal-actions">
128 <Button variant="tertiary" onClick={() => onAfterSave(false)}>
129 {__('Cancel', 'extendify-local')}
130 </Button>
131 <Button
132 variant="primary"
133 isBusy={saving}
134 disabled={saving || !data}
135 onClick={handleSave}
136 >
137 {__('Save', 'extendify-local')}
138 </Button>
139 </div>
140 </Modal>
141 );
142 };
143