import {__} from '@wordpress/i18n'; import {ListTablePage} from '@givewp/components'; import {DonationRowActions} from './DonationRowActions'; import ListTableApi from '@givewp/components/ListTable/api'; import tableStyles from '@givewp/components/ListTable/ListTablePage/ListTablePage.module.scss'; import styles from './ListTable.module.scss'; import {IdBadge} from '@givewp/components/ListTable/TableCell'; import {BulkActionsConfig, FilterConfig} from '@givewp/components/ListTable/ListTablePage'; import {Interweave} from 'interweave'; import BlankSlate from '@givewp/components/ListTable/BlankSlate'; import ProductRecommendations from '@givewp/components/ListTable/ProductRecommendations'; import {RecommendedProductData} from '@givewp/promotions/hooks/useRecommendations'; import { StatConfig } from '@givewp/components/ListTable/ListTableStats/ListTableStats'; import filterByOptions from '../constants/filterByOptions'; declare global { interface Window { GiveDonations: { apiNonce: string; apiRoot: string; adminUrl: string; campaigns: Array<{value: string; text: string}>; table: {columns: Array}; paymentMode: boolean; manualDonations: boolean; recurringDonationsEnabled: boolean; pluginUrl: string; dismissedRecommendations: Array; addonsBulkActions: Array; donationStatuses: {[statusCode: string]: string}; }; } } const API = new ListTableApi(window.GiveDonations); const filters: Array = [ { name: 'campaignId', type: 'campaignselect', text: __('Select Campaign', 'give'), ariaLabel: __('filter donations by campaign', 'give'), }, { name: 'search', type: 'search', inlineSize: '14rem', text: __('Name, Email, or Donation ID', 'give'), ariaLabel: __('search donations', 'give'), }, { name: 'toggle', type: 'checkbox', text: __('Test', 'give'), ariaLabel: __('View Test Donations', 'give'), }, { name: 'donor', type: 'hidden', }, { name: 'filterBy', type: 'filterby', groupedOptions: filterByOptions, }, ]; const bulkActions: Array = [ { label: __('Delete', 'give'), value: 'delete', type: 'danger', isVisible: (data, parameters) => parameters?.status?.includes('trash'), action: async (selected) => { const response = await API.fetchWithArgs('/delete', {ids: selected.join(',')}, 'DELETE'); return response; }, confirm: (selected, names) => ( <>

{__('Really delete the following donations?', 'give')}

    {selected.map((donationId, index) => (
  • {' '} {__('from ', 'give')}
  • ))}
), }, { label: __('Trash', 'give'), value: 'trash', type: 'warning', isVisible: (data, parameters) => !parameters?.status?.includes('trash'), action: async (selected) => { const response = await API.fetchWithArgs('/trash', {ids: selected.join(',')}, 'DELETE'); return response; }, confirm: (selected, names) => ( <>

{__('Are you sure you want add to trash the following donations?', 'give')}

    {selected.map((donationId, index) => (
  • {' '} {__('from ', 'give')}
  • ))}
), }, { label: __('Restore', 'give'), value: 'restore', type: 'normal', isVisible: (data, parameters) => parameters?.status?.includes('trash'), action: async (selected) => { const response = await API.fetchWithArgs('/untrash', {ids: selected.join(',')}, 'POST'); return response; }, confirm: (selected, names) => ( <>

{__('Are you sure you want remove from trash the following donations?', 'give')}

    {selected.map((donationId, index) => (
  • {' '} {__('from ', 'give')}
  • ))}
), }, ...(() => { const donationStatuses = { publish: __('Set To Completed', 'give'), pending: __('Set To Pending', 'give'), processing: __('Set To Processing', 'give'), refunded: __('Set To Refunded', 'give'), revoked: __('Set To Revoked', 'give'), failed: __('Set To Failed', 'give'), cancelled: __('Set To Cancelled', 'give'), abandoned: __('Set To Abandoned', 'give'), preapproval: __('Set To Preapproval', 'give'), }; return Object.entries(donationStatuses).map(([value, label]) => { return { label, value, isVisible: (data, parameters) => !parameters?.status?.includes('trash'), action: async (selected) => await API.fetchWithArgs( '/setStatus', { ids: selected.join(','), status: value, }, 'POST' ), confirm: (selected, names) => ( <>

{__('Set status for the following donations?', 'give')}

    {selected.map((donationId, index) => (
  • {__('from', 'give')}
  • ))}
), }; }); })(), { label: __('Resend Email Receipts', 'give'), value: 'resendEmailReceipt', action: async (selected) => await API.fetchWithArgs('/resendEmailReceipt', {ids: selected.join(',')}, 'POST'), confirm: (selected, names) => ( <>

{__('Resend Email Receipts for following donations?', 'give')}

    {selected.map((donationId, index) => (
  • {__('from', 'give')}
  • ))}
), }, ]; /** * Displays a blank slate for the Donations table. * @since 2.27.0 */ const ListTableBlankSlate = ( ); interface DonationTableRecommendations { recurring: RecommendedProductData; feeRecovery: RecommendedProductData; designatedFunds: RecommendedProductData; } /** * @since 2.27.1 */ const RecommendationConfig: DonationTableRecommendations = { recurring: { enum: 'givewp_donations_recurring_recommendation_dismissed', documentationPage: 'https://docs.givewp.com/recurring-donations-list', message: __('Increase your fundraising revenue by over 30% with recurring giving campaigns.', 'give'), innerHtml: __('Get More Donations', 'give'), }, feeRecovery: { enum: 'givewp_donations_fee_recovery_recommendation_dismissed', documentationPage: 'https://docs.givewp.com/feerecovery-donations-list', message: __( 'Raise more money per donation by providing donors with the option to help cover the credit card processing fees.', 'give' ), innerHtml: __('Get Fee Recovery', 'give'), }, designatedFunds: { enum: 'givewp_donations_designated_funds_recommendation_dismissed', documentationPage: 'https://docs.givewp.com/funds-donations-list', message: __( 'Elevate your fundraising campaigns with unlimited donation fund designations, and tailored fundraising reports.', 'give' ), innerHtml: __('Start creating designated funds', 'give'), }, }; const rotatingRecommendation = ( ); /** * Configuration for the statistic tiles rendered above the ListTable. * * IMPORTANT: Object keys MUST MATCH the keys returned by the API's `stats` payload. * For example, if the API returns: * * data.stats = { * donationsCount: number; * oneTimeDonationsCount: number; * recurringDonationsCount: number; * } * * then this config must use those same keys: "donationsCount", "oneTimeDonationsCount", "recurringDonationsCount". * Missing or mismatched keys will result in empty/undefined values in the UI. * * @since 4.10.0 */ const statsConfig: Record = { donationsCount: { label: __('Total Donations', 'give')}, oneTimeDonationsCount: { label: __('One-Time Donations', 'give')}, recurringDonationsCount: { label: __('Recurring Donations', 'give'), upgrade: !window.GiveDonations.recurringDonationsEnabled && { href: 'https://docs.givewp.com/recurring-stat', tooltip: __('Increase your fundraising revenue by over 30% with recurring giving campaigns.', 'give') } }, }; /** * @since 4.10.0 Update button class names and add aria attributes. * @since 2.24.0 */ export default function DonationsListTable() { return ( {window.GiveDonations.manualDonations ? ( {__('New donation', 'give')} ) : ( {__('ADD-ON', 'give')} {__('Enter donations', 'give')} {__('Information',{' '} {__( 'Need to add in a record for a donation received elsewhere, or reconcile with the payment gateway? Add donation records with the Manual Donations add-on!', 'give' )} )} {__('Import donations', 'give')} ); } const showLegacyDonations = async (event) => { await API.fetchWithArgs('/view', {isLegacy: 1}); window.location.reload(); };