ListTable.tsx
252 lines
| 1 | import {__, sprintf} from '@wordpress/i18n'; |
| 2 | import {useSWRConfig} from 'swr'; |
| 3 | import {ListTableColumn, ListTablePage} from '@givewp/components'; |
| 4 | import RowAction from "@givewp/components/ListTable/RowAction"; |
| 5 | import ListTableApi from '@givewp/components/ListTable/api'; |
| 6 | import tableStyles from "@givewp/components/ListTable/ListTablePage.module.scss"; |
| 7 | import styles from './ListTable.module.scss'; |
| 8 | import {IdBadge} from "@givewp/components/ListTable/TableCell"; |
| 9 | import {BulkActionsConfig, FilterConfig, ShowConfirmModalContext} from "@givewp/components/ListTable"; |
| 10 | import {useContext} from "react"; |
| 11 | import {DonationType} from "@givewp/components/ListTable/TypeBadge"; |
| 12 | |
| 13 | declare global { |
| 14 | interface Window { |
| 15 | GiveDonations; |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | const API = new ListTableApi(window.GiveDonations); |
| 20 | |
| 21 | export default function () { |
| 22 | const {mutate} = useSWRConfig(); |
| 23 | |
| 24 | const rowActions = ({item, removeRow, setUpdateErrors, parameters}) => { |
| 25 | const showConfirmModal = useContext(ShowConfirmModalContext); |
| 26 | |
| 27 | const fetchAndUpdateErrors = async (parameters, endpoint, id, method) => { |
| 28 | const response = await API.fetchWithArgs(endpoint, {ids: [id]}, method); |
| 29 | setUpdateErrors(response); |
| 30 | await mutate(parameters); |
| 31 | return response; |
| 32 | } |
| 33 | |
| 34 | const deleteItem = async (selected) => await fetchAndUpdateErrors(parameters, '/delete', item.id, 'DELETE'); |
| 35 | |
| 36 | const confirmDelete = (selected) => ( |
| 37 | <p> |
| 38 | {sprintf(__('Really delete donation #%d?', 'give'), item.id)} |
| 39 | </p> |
| 40 | ); |
| 41 | |
| 42 | const confirmModal = (event) => { |
| 43 | showConfirmModal(__('Delete', 'give'), confirmDelete, deleteItem, 'danger'); |
| 44 | } |
| 45 | |
| 46 | return ( |
| 47 | <> |
| 48 | <RowAction |
| 49 | href={window.GiveDonations.adminUrl + `edit.php?post_type=give_forms&page=give-payment-history&view=view-payment-details&id=${item.id}`} |
| 50 | displayText={__('View/Edit', 'give')} |
| 51 | /> |
| 52 | <RowAction |
| 53 | onClick={confirmModal} |
| 54 | actionId={item.id} |
| 55 | displayText={__('Delete', 'give')} |
| 56 | hiddenText={item.name} |
| 57 | highlight |
| 58 | /> |
| 59 | </> |
| 60 | ); |
| 61 | } |
| 62 | |
| 63 | const columns: Array<ListTableColumn> = [ |
| 64 | { |
| 65 | name: 'id', |
| 66 | text: __('ID', 'give'), |
| 67 | heading: true, |
| 68 | alignColumn: 'start', |
| 69 | inlineSize: '5rem', |
| 70 | preset: 'idBadge' |
| 71 | }, |
| 72 | { |
| 73 | name: 'amount', |
| 74 | text: __('Amount', 'give'), |
| 75 | inlineSize: '7rem', |
| 76 | preset: 'monetary', |
| 77 | }, |
| 78 | { |
| 79 | name: 'paymentType', |
| 80 | text: __('Payment Type'), |
| 81 | inlineSize: '11rem', |
| 82 | addClass: styles.paymentType, |
| 83 | render: (donation: {donationType}) => ( |
| 84 | <DonationType type={donation.donationType}/> |
| 85 | ) |
| 86 | }, |
| 87 | { |
| 88 | name: 'createdAt', |
| 89 | inlineSize: '9rem', |
| 90 | text: __('Date / Time', 'give'), |
| 91 | }, |
| 92 | { |
| 93 | name: 'name', |
| 94 | text: __('Donor Name', 'give'), |
| 95 | inlineSize: '9rem', |
| 96 | render: (donation: { name, donorId }) => ( |
| 97 | <a href={window.GiveDonations.adminUrl + `edit.php?post_type=give_forms&page=give-donors&view=overview&id=${donation.donorId}`}> |
| 98 | {donation.name} |
| 99 | </a> |
| 100 | ), |
| 101 | }, |
| 102 | { |
| 103 | name: 'formTitle', |
| 104 | text: __('Donation Form', 'give'), |
| 105 | inlineSize: '9rem', |
| 106 | render: (donation: { formTitle, formId }) => ( |
| 107 | <a href={window.GiveDonations.adminUrl + `post.php?post=${donation.formId}&action=edit`}> |
| 108 | {donation.formTitle} |
| 109 | </a> |
| 110 | ) |
| 111 | }, |
| 112 | { |
| 113 | name: 'gateway', |
| 114 | inlineSize: '11rem', |
| 115 | text: __('Gateway', 'give'), |
| 116 | }, |
| 117 | { |
| 118 | name: 'status', |
| 119 | text: __('Status', 'give'), |
| 120 | inlineSize: '12rem', |
| 121 | preset: 'donationStatus', |
| 122 | }, |
| 123 | ]; |
| 124 | |
| 125 | const filters: Array<FilterConfig> = [ |
| 126 | { |
| 127 | name: 'search', |
| 128 | type: 'search', |
| 129 | inlineSize: '14rem', |
| 130 | text: __('Name, Email, or Donation ID', 'give'), |
| 131 | ariaLabel: __('search donations', 'give'), |
| 132 | }, |
| 133 | { |
| 134 | name: 'form', |
| 135 | type: 'formselect', |
| 136 | text: __('Select Form', 'give'), |
| 137 | ariaLabel: __('filter donation forms by status', 'give'), |
| 138 | options: window.GiveDonations.forms, |
| 139 | } |
| 140 | ] |
| 141 | |
| 142 | const bulkActions: Array<BulkActionsConfig> = [ |
| 143 | { |
| 144 | label: __('Delete', 'give'), |
| 145 | value: 'delete', |
| 146 | type: 'danger', |
| 147 | action: async (selected) => { |
| 148 | const response = await API.fetchWithArgs('/delete', {ids: selected.join(',')}, 'DELETE'); |
| 149 | return response; |
| 150 | }, |
| 151 | confirm: (selected, names) => ( |
| 152 | <> |
| 153 | <p>{__('Really delete the following donations?', 'give')}</p> |
| 154 | <ul role='document' tabIndex={0}> |
| 155 | {selected.map((donationId, index) => ( |
| 156 | <li key={donationId}> |
| 157 | <IdBadge id={donationId}/> |
| 158 | {' '} |
| 159 | <span>{sprintf(__('from %s', 'give'), names[index])}</span> |
| 160 | </li> |
| 161 | ))} |
| 162 | </ul> |
| 163 | </> |
| 164 | ) |
| 165 | }, |
| 166 | ...(() => { |
| 167 | const donationStatuses = { |
| 168 | 'publish': __('Set To Completed', 'give'), |
| 169 | 'pending': __('Set To Pending', 'give'), |
| 170 | 'processing': __('Set To Processing', 'give'), |
| 171 | 'refunded': __('Set To Refunded', 'give'), |
| 172 | 'revoked': __('Set To Revoked', 'give'), |
| 173 | 'failed': __('Set To Failed', 'give'), |
| 174 | 'cancelled': __('Set To Cancelled', 'give'), |
| 175 | 'abandoned': __('Set To Abandoned', 'give'), |
| 176 | 'preapproval': __('Set To Preapproval', 'give') |
| 177 | }; |
| 178 | |
| 179 | return Object.entries(donationStatuses).map(([value, label]) => { |
| 180 | return { |
| 181 | label, |
| 182 | value, |
| 183 | action: async (selected) => await API.fetchWithArgs('/setStatus', { |
| 184 | ids: selected.join(','), |
| 185 | status: value |
| 186 | }, 'POST'), |
| 187 | confirm: (selected, names) => ( |
| 188 | <> |
| 189 | <p>{__('Set status for the following donations?', 'give')}</p> |
| 190 | <ul role='document' tabIndex={0}> |
| 191 | {selected.map((donationId, index) => ( |
| 192 | <li key={donationId}> |
| 193 | <IdBadge id={donationId}/> |
| 194 | {' '} |
| 195 | <span>{sprintf(__('from %s', 'give'), names[index])}</span> |
| 196 | </li> |
| 197 | ))} |
| 198 | </ul> |
| 199 | </> |
| 200 | ) |
| 201 | }; |
| 202 | }); |
| 203 | })(), |
| 204 | { |
| 205 | label: __('Resend Email Receipts', 'give'), |
| 206 | value: 'resendEmailReceipt', |
| 207 | action: async (selected) => await API.fetchWithArgs('/resendEmailReceipt', {ids: selected.join(',')}, 'POST'), |
| 208 | confirm: (selected, names) => ( |
| 209 | <> |
| 210 | <p>{__('Resend Email Receipts for following donations?', 'give')}</p> |
| 211 | <ul role='document' tabIndex={0}> |
| 212 | {selected.map((donationId, index) => ( |
| 213 | <li key={donationId}> |
| 214 | <IdBadge id={donationId}/> |
| 215 | {' '} |
| 216 | <span>{sprintf(__('from %s', 'give'), names[index])}</span> |
| 217 | </li> |
| 218 | ))} |
| 219 | </ul> |
| 220 | </> |
| 221 | ) |
| 222 | } |
| 223 | ] |
| 224 | |
| 225 | return ( |
| 226 | <ListTablePage |
| 227 | title={__('Donations', 'give')} |
| 228 | singleName={__('donation', 'give')} |
| 229 | pluralName={__('donations', 'give')} |
| 230 | columns={columns} |
| 231 | rowActions={rowActions} |
| 232 | bulkActions={bulkActions} |
| 233 | apiSettings={window.GiveDonations} |
| 234 | filterSettings={filters} |
| 235 | > |
| 236 | <a className={tableStyles.addFormButton} |
| 237 | href={window.GiveDonations.adminUrl + 'edit.php?post_type=give_forms&page=give-tools&tab=import&importer-type=import_donations'} |
| 238 | > |
| 239 | {__('Import Donations', 'give')} |
| 240 | </a> |
| 241 | <button className={tableStyles.addFormButton} onClick={showLegacyDonations}> |
| 242 | {__('Switch to Legacy View')} |
| 243 | </button> |
| 244 | </ListTablePage> |
| 245 | ) |
| 246 | } |
| 247 | |
| 248 | const showLegacyDonations = async (event) => { |
| 249 | await API.fetchWithArgs('/view', {isLegacy: 1}); |
| 250 | window.location.reload(); |
| 251 | } |
| 252 |