PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 4.7.0
GiveWP – Donation Plugin and Fundraising Platform v4.7.0
4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / DonationForms / V2 / resources / components / DonationFormsListTable.tsx
give / src / DonationForms / V2 / resources / components Last commit date
AddCampaignFormModal 1 year ago Migration 1 year ago Onboarding 1 year ago DonationFormsListTable.tsx 11 months ago DonationFormsRowActions.tsx 1 year ago
DonationFormsListTable.tsx
393 lines
1 import {useState} from 'react';
2 import {__} from '@wordpress/i18n';
3 import {ListTableApi, ListTablePage} from '@givewp/components';
4 import {DonationFormsRowActions} from './DonationFormsRowActions';
5 import Onboarding, {OnboardingContext, OnboardingStateProps} from './Onboarding';
6 import styles from '@givewp/components/ListTable/ListTablePage/ListTablePage.module.scss';
7 import {BulkActionsConfig, ColumnFilterConfig, FilterConfig} from '@givewp/components/ListTable/ListTablePage';
8 import Select from '@givewp/components/ListTable/Select';
9 import {Interweave} from 'interweave';
10 import InterweaveSSR from '@givewp/components/ListTable/InterweaveSSR';
11 import BlankSlate from '@givewp/components/ListTable/BlankSlate';
12 import {CubeIcon} from '@givewp/components/AdminUI/Icons';
13 import AddCampaignFormModal from './AddCampaignFormModal';
14 import DefaultFormNotice from '@givewp/campaigns/admin/components/CampaignDetailsPage/Components/Notices/DefaultFormNotice';
15 import apiFetch from '@wordpress/api-fetch';
16 import {CampaignEntity} from '@givewp/campaigns/admin/components/types';
17
18 declare global {
19 interface Window {
20 GiveDonationForms: {
21 apiNonce: string;
22 bannerActionUrl: string;
23 tooltipActionUrl: string;
24 migrationApiRoot: string;
25 defaultFormActionUrl: string;
26 apiRoot: string;
27 authors: Array<{id: string | number; name: string}>;
28 table: {columns: Array<object>};
29 pluginUrl: string;
30 showUpgradedTooltip: boolean;
31 isMigrated: boolean;
32 supportedAddons: Array<string>;
33 supportedGateways: Array<string>;
34 isOptionBasedFormEditorEnabled: boolean;
35 locale: string;
36 showDefaultFormTooltip: boolean;
37 campaignUrl: string;
38 };
39
40 GiveNextGen?: {
41 newFormUrl: string;
42 };
43 }
44 }
45
46 const API = new ListTableApi(window.GiveDonationForms);
47
48 const donationStatus = [
49 {
50 value: 'any',
51 text: __('All Status', 'give'),
52 },
53 {
54 value: 'publish',
55 text: __('Published', 'give'),
56 },
57 {
58 value: 'pending',
59 text: __('Pending', 'give'),
60 },
61 {
62 value: 'draft',
63 text: __('Draft', 'give'),
64 },
65 {
66 value: 'trash',
67 text: __('Trash', 'give'),
68 },
69 {
70 value: 'upgraded',
71 text: __('Upgraded', 'give'),
72 },
73 ];
74
75 const urlParams = new URLSearchParams(window.location.search);
76
77 const isCampaignDetailsPage = urlParams.get('id') && 'give-campaigns' === urlParams.get('page');
78 const campaignId = urlParams.get('id');
79
80 const donationFormsFilters: Array<FilterConfig> = [
81 {
82 name: 'status',
83 type: 'select',
84 text: __('status', 'give'),
85 ariaLabel: __('Filter donation forms by status', 'give'),
86 options: donationStatus,
87 },
88 {
89 name: 'search',
90 type: 'search',
91 text: __('Search by name or ID', 'give'),
92 ariaLabel: __('Search donation forms', 'give'),
93 },
94 ];
95
96 if (isCampaignDetailsPage) {
97 donationFormsFilters.push({
98 name: 'campaignId',
99 type: 'select',
100 text: __('Campaign ID', 'give'),
101 ariaLabel: __('Filter donation forms by Campaign ID', 'give'),
102 options: [
103 {
104 value: campaignId,
105 text: __('All Campaign Forms', 'give'),
106 },
107 ],
108 });
109 }
110
111 /**
112 * @since 4.6.0 add option based form editor enabled check.
113 */
114 const columnFilters: Array<ColumnFilterConfig> = [
115 {
116 column: 'title',
117 filter: (item) => {
118 const CubeTooltip = () => (
119 <div className={styles.tooltipContainer}>
120 <CubeIcon />
121 <div className={styles.tooltip}>{__('Uses the Visual Form Builder', 'give')}</div>
122 </div>
123 );
124
125 return (
126 <>
127 <div className={styles.titleContainer}>
128 <div className={styles.migratedForm}>
129 {item?.v3form && window?.GiveDonationForms?.isOptionBasedFormEditorEnabled && <CubeTooltip />}
130 <Interweave attributes={{className: 'interweave'}} content={item?.title} />
131 </div>
132 {item?.isDefaultCampaignForm && (
133 <div className={`${styles.defaultFormPill} givewp-default-form-pill`}>{__('Default')}</div>
134 )}
135 </div>
136 </>
137 );
138 },
139 },
140 {
141 column: 'status',
142 filter: (item, column) => {
143 if (window.GiveDonationForms.showUpgradedTooltip && item?.status_raw === 'upgraded') {
144 return (
145 <div className={styles.upgradedForm}>
146 <div className={styles.tooltipContainer}>
147 <div className={styles.tooltip}>
148 {__(
149 'The name of this form is already associated with an upgraded form. You can safely delete this form',
150 'give'
151 )}
152 .
153 <div
154 className={styles.link}
155 onClick={(e) => {
156 e.currentTarget.parentElement.remove();
157 fetch(window.GiveDonationForms.tooltipActionUrl, {method: 'POST'});
158 }}
159 >
160 {__('Got it', 'give')}
161 </div>
162 </div>
163 </div>
164 <InterweaveSSR column={column} item={item} />
165 </div>
166 );
167 }
168
169 return <InterweaveSSR column={column} item={item} />;
170 },
171 },
172 ];
173
174 const donationFormsBulkActions: Array<BulkActionsConfig> = [
175 {
176 label: __('Edit', 'give'),
177 value: 'edit',
178 action: async (selected) => {
179 const authorSelect = document.getElementById('giveDonationFormsTableSetAuthor') as HTMLSelectElement;
180 const author = authorSelect.value;
181 const statusSelect = document.getElementById('giveDonationFormsTableSetStatus') as HTMLSelectElement;
182 const status = statusSelect.value;
183 if (!(author || status)) {
184 return {errors: [], successes: []};
185 }
186 const editParams = {
187 ids: selected.join(','),
188 author,
189 status,
190 };
191 return await API.fetchWithArgs('/edit', editParams, 'UPDATE');
192 },
193 confirm: (selected, names) => (
194 <>
195 <p>{__(' Below are the donation forms to be edited.', 'give')}</p>
196 <ul role="document" tabIndex={0}>
197 {selected.map((id, index) => (
198 <li key={id}>
199 <Interweave content={names[index]} />
200 </li>
201 ))}
202 </ul>
203 <div className={styles.flexRow}>
204 <label htmlFor="giveDonationFormsTableSetAuthor">{__('Set form author', 'give')}</label>
205 <Select id="giveDonationFormsTableSetAuthor" style={{paddingInlineEnd: '2rem'}}>
206 <option value="">{__('Keep current author', 'give')}</option>
207 {window.GiveDonationForms.authors.map((author) => (
208 <option key={author.id} value={author.id}>
209 {author.name}
210 </option>
211 ))}
212 </Select>
213 </div>
214 <div className={styles.flexRow}>
215 <label htmlFor="giveDonationFormsTableSetStatus">{__('Set form status', 'give')}</label>
216 <Select id="giveDonationFormsTableSetStatus" style={{paddingInlineEnd: '2rem'}}>
217 <option value="">{__('Keep current status')}</option>
218 <option value="publish">{__('Published', 'give')}</option>
219 <option value="private">{__('Private', 'give')}</option>
220 <option value="pending">{__('Pending Review', 'give')}</option>
221 <option value="draft">{__('Draft', 'give')}</option>
222 </Select>
223 </div>
224 </>
225 ),
226 },
227 {
228 label: __('Delete', 'give'),
229 value: 'delete',
230 type: 'danger',
231 isVisible: (data, parameters) => parameters.status === 'trash' || !data?.trash,
232 action: async (selected) => {
233 try {
234 return await API.fetchWithArgs('/delete', {ids: selected.join(',')}, 'DELETE');
235 } catch (error) {
236 const errorData = JSON.parse(error.message.replace('Error: ', ''));
237 alert(errorData.message);
238 }
239 },
240 confirm: (selected, names) => (
241 <div>
242 <p>{__('Really delete the following donation forms?', 'give')}</p>
243 <ul role="document" tabIndex={0}>
244 {selected.map((id, index) => (
245 <li key={id}>
246 <Interweave content={names[index]} />
247 </li>
248 ))}
249 </ul>
250 </div>
251 ),
252 },
253 {
254 label: __('Trash', 'give'),
255 value: 'trash',
256 type: 'danger',
257 isVisible: (data, parameters) => parameters.status !== 'trash' && data?.trash,
258 isIdSelectable: (id, data) => !(typeof data?.defaultForm === 'number') || data.defaultForm !== Number(id),
259 action: async (selected) => {
260 try {
261 return await API.fetchWithArgs('/trash', {ids: selected.join(',')}, 'DELETE');
262 } catch (error) {
263 const errorData = JSON.parse(error.message.replace('Error: ', ''));
264 alert(errorData.message);
265 }
266 },
267 confirm: (selected, names) => (
268 <div>
269 <p>{__('Are you sure you want to trash the following donation forms?', 'give')}</p>
270 <ul role="document" tabIndex={0}>
271 {selected.map((id, index) => (
272 <li key={id}>
273 <Interweave content={names[index]} />
274 </li>
275 ))}
276 </ul>
277 </div>
278 ),
279 },
280 ];
281
282 /**
283 * Displays a blank slate for the Forms table.
284 * @since 2.27.0
285 */
286 const ListTableBlankSlate = (
287 <BlankSlate
288 imagePath={`${window.GiveDonationForms.pluginUrl}build/assets/dist/images/list-table/blank-slate-donation-forms-icon.svg`}
289 description={__('No donation forms', 'give')}
290 href={'https://docs.givewp.com/forms'}
291 linkText={__('GiveWP Forms', 'give')}
292 />
293 );
294
295 export default function DonationFormsListTable({entity}: {entity?: CampaignEntity}) {
296 const [state, setState] = useState<OnboardingStateProps>({
297 showFeatureNoticeDialog: false,
298 showDefaultFormTooltip: window.GiveDonationForms.showDefaultFormTooltip,
299 });
300
301 const handleDefaultFormTooltipDismiss = () => {
302 apiFetch({
303 url: window.GiveDonationForms.defaultFormActionUrl,
304 method: 'POST',
305 }).then(() => {
306 setState((prevState) => {
307 return {
308 ...prevState,
309 showDefaultFormTooltip: false,
310 };
311 });
312 });
313 };
314
315 const [isOpen, setOpen] = useState<boolean>(false);
316 const openModal = () => setOpen(true);
317 const closeModal = () => setOpen(false);
318
319 return (
320 <OnboardingContext.Provider value={[state, setState]}>
321 <ListTablePage
322 title={__('Donation Forms', 'give')}
323 singleName={__('donation form', 'give')}
324 pluralName={__('donation forms', 'give')}
325 rowActions={({data, item, removeRow, addRow, setUpdateErrors, parameters}) => {
326 return DonationFormsRowActions({
327 data,
328 item,
329 removeRow,
330 addRow,
331 setUpdateErrors,
332 parameters,
333 entity,
334 });
335 }}
336 bulkActions={donationFormsBulkActions}
337 apiSettings={window.GiveDonationForms}
338 filterSettings={donationFormsFilters}
339 listTableBlankSlate={ListTableBlankSlate}
340 columnFilters={columnFilters}
341 banner={Onboarding}
342 contentMode={isCampaignDetailsPage}
343 >
344 {isCampaignDetailsPage ? (
345 <div className={`${styles.flexRow} ${styles.justifyContentEnd}`}>
346 {window.GiveDonationForms.isOptionBasedFormEditorEnabled ? (
347 <>
348 <button className={styles.addCampaignFormButton} onClick={openModal}>
349 {__('Add campaign form', 'give')}
350 </button>
351 <AddCampaignFormModal
352 isOpen={isOpen}
353 handleClose={closeModal}
354 title={__('Choose how you want to edit your campaign form', 'give')}
355 campaignId={campaignId}
356 />
357 </>
358 ) : (
359 <>
360 <a
361 href={`edit.php?post_type=give_forms&page=givewp-form-builder&donationFormID=new&locale=${window.GiveDonationForms.locale}&campaignId=${campaignId}`}
362 className={styles.addCampaignFormButton}
363 >
364 {__('Add campaign form', 'give')}
365 </a>
366 </>
367 )}
368 </div>
369 ) : (
370 <>
371 {window.GiveDonationForms.isOptionBasedFormEditorEnabled && (
372 <button
373 className={`button button-secondary ${styles.button} ${styles.buttonSecondary}`}
374 onClick={showLegacyDonationForms}
375 >
376 {__('Switch to Legacy View', 'give')}
377 </button>
378 )}
379 </>
380 )}
381 {state.showDefaultFormTooltip && isCampaignDetailsPage && (
382 <DefaultFormNotice handleClick={handleDefaultFormTooltipDismiss} />
383 )}
384 </ListTablePage>
385 </OnboardingContext.Provider>
386 );
387 }
388
389 const showLegacyDonationForms = async (event) => {
390 await API.fetchWithArgs('/view', {isLegacy: 1});
391 window.location.href = '/wp-admin/edit.php?post_type=give_forms';
392 };
393