Skip to content

Commit

Permalink
Feature: Add Campaign Donors block (#7700)
Browse files Browse the repository at this point in the history
  • Loading branch information
pauloiankoski authored Feb 6, 2025
1 parent d149099 commit 3056b51
Show file tree
Hide file tree
Showing 24 changed files with 1,018 additions and 316 deletions.
514 changes: 267 additions & 247 deletions package-lock.json

Large diffs are not rendered by default.

20 changes: 18 additions & 2 deletions src/Campaigns/Actions/RegisterCampaignBlocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ public function __invoke()

array_map('register_block_type', $blocks);

$this->enqueueBlocksAssets();
if (is_admin()) {
$this->enqueueAdminBlocksAssets();
}

$this->registerSharedStyles();
}

/**
* @unreleased
*/
private function enqueueBlocksAssets()
private function enqueueAdminBlocksAssets(): void
{
$handleName = 'givewp-campaign-blocks';
$scriptAsset = ScriptAsset::get(GIVE_PLUGIN_DIR . 'build/campaignBlocks.asset.php');
Expand All @@ -46,4 +50,16 @@ private function enqueueBlocksAssets()
$scriptAsset['version']
);
}

/**
* @unreleased
*/
private function registerSharedStyles(): void
{
wp_enqueue_style('givewp-design-system-foundation');
wp_enqueue_style(
'givewp-campaign-blocks-fonts',
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'
);
}
}
18 changes: 10 additions & 8 deletions src/Campaigns/Blocks/CampaignCover/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import metadata from './block.json';
import schema from './block.json';
import Edit from './edit';
import initBlock from '../shared/utils/init-block';
import {GalleryIcon} from './Icon';

const {name} = metadata;

export {metadata, name};
export const settings = {
edit: Edit,
/**
* @unreleased
*/
const settings = {
icon: <GalleryIcon />,
edit: Edit,
};

export const init = () => initBlock({name, metadata, settings});
export default {
schema,
settings,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace Give\Campaigns\Blocks\CampaignDonors;

use Give\Campaigns\Models\Campaign;
use Give\Framework\Support\ValueObjects\Money;
use Give\Framework\Views\View;

/**
* @unreleased
*/
class CampaignDonorsBlockViewModel
{
/**
* @var Campaign $campaign
*/
private $campaign;

/**
* @var array
*/
private $donors;

/**
* @var array $attributes
*/
private $attributes;

/**
* @unreleased
*/
public function __construct(Campaign $campaign, array $donors, array $attributes)
{
$this->attributes = $attributes;
$this->campaign = $campaign;
$this->donors = $donors;
}

/**
* @unreleased
*/
public function render(): void
{
View::render('Campaigns/Blocks/CampaignDonors.render', [
'campaign' => $this->campaign,
'donors' => $this->formatDonorsData($this->donors),
'attributes' => $this->attributes,
]);
}


/**
* @unreleased
*/
private function formatDonorsData(array $donors): array
{
return array_map(static function ($entry) {
if (isset($entry->date)) {
$entry->date = human_time_diff(strtotime($entry->date));
}
$entry->amount = Money::fromDecimal($entry->amount, give_get_currency());

return $entry;
}, $donors);
}
}
1 change: 1 addition & 0 deletions src/Campaigns/Blocks/CampaignDonors/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './styles.scss';
52 changes: 52 additions & 0 deletions src/Campaigns/Blocks/CampaignDonors/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "givewp/campaign-donors",
"version": "1.0.0",
"title": "Campaign Donors",
"category": "give",
"description": "Display all the donors associated with a campaign.",
"attributes": {
"campaignId": {
"type": "integer"
},
"showAnonymous": {
"type": "boolean",
"default": true
},
"showCompanyName": {
"type": "boolean",
"default": true
},
"showAvatar": {
"type": "boolean",
"default": true
},
"showButton": {
"type": "boolean",
"default": true
},
"donateButtonText": {
"type": "string",
"default": "Join the list"
},
"sortBy": {
"type": "string",
"default": "top-donors"
},
"donorsPerPage": {
"type": "number",
"default": 5
},
"loadMoreButtonText": {
"type": "string",
"default": "Load more"
}
},
"supports": {
"className": true
},
"textdomain": "give",
"render": "file:./render.php",
"style": "file:../../../../build/campaignDonorsBlockApp.css"
}
112 changes: 112 additions & 0 deletions src/Campaigns/Blocks/CampaignDonors/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import {InspectorControls, useBlockProps} from '@wordpress/block-editor';
import {BlockEditProps} from '@wordpress/blocks';
import {
__experimentalNumberControl as NumberControl,
PanelBody,
SelectControl,
TextControl,
ToggleControl,
} from '@wordpress/components';
import {__} from '@wordpress/i18n';
import ServerSideRender from '@wordpress/server-side-render';
import {CampaignSelector} from '../shared/components/CampaignSelector';
import useCampaign from '../shared/hooks/useCampaign';

export default function Edit({
attributes,
setAttributes,
}: BlockEditProps<{
campaignId: number;
showAnonymous: boolean;
showCompanyName: boolean;
showAvatar: boolean;
showButton: boolean;
donateButtonText: string;
sortBy: string;
donorsPerPage: number;
loadMoreButtonText: string;
}>) {
const blockProps = useBlockProps();
const {campaign, hasResolved} = useCampaign(attributes.campaignId);

const {
showAnonymous,
showCompanyName,
showAvatar,
showButton,
donateButtonText,
sortBy,
donorsPerPage,
loadMoreButtonText,
} = attributes;

return (
<div {...blockProps}>
<CampaignSelector attributes={attributes} setAttributes={setAttributes}>
<ServerSideRender block="givewp/campaign-donors" attributes={attributes} />
</CampaignSelector>

{hasResolved && campaign?.id && (
<InspectorControls>
<PanelBody title={__('Display Elements', 'give')} initialOpen={true}>
<ToggleControl
label={__('Show anonymous', 'give')}
checked={showAnonymous}
onChange={(value) => setAttributes({showAnonymous: value})}
/>
<ToggleControl
label={__('Show company name', 'give')}
checked={showCompanyName}
onChange={(value) => setAttributes({showCompanyName: value})}
/>
<ToggleControl
label={__('Show avatar', 'give')}
checked={showAvatar}
onChange={(value) => setAttributes({showAvatar: value})}
/>
<ToggleControl
label={__('Show button', 'give')}
checked={showButton}
onChange={(value) => setAttributes({showButton: value})}
/>
<TextControl
label={__('Donate Button', 'give')}
value={donateButtonText}
onChange={(value) => setAttributes({donateButtonText: value})}
help={__('This shows on the header', 'give')}
/>
</PanelBody>

<PanelBody title={__('Settings', 'give')} initialOpen={true}>
<SelectControl
label={__('Sort by', 'give')}
value={sortBy}
options={[
{label: __('Top Donors', 'give'), value: 'top-donors'},
{label: __('Recent Donors', 'give'), value: 'recent-donors'},
]}
onChange={(value) => setAttributes({sortBy: value})}
help={__('The order donors are displayed in.', 'give')}
/>
{/* TODO: Revert the label and help text back to what are in the designs once the backend for pagination is ready */}
<NumberControl
label={__('Limit', 'give')}
value={donorsPerPage}
min={1}
max={100}
onChange={(value) => setAttributes({donorsPerPage: parseInt(value)})}
help={__('The maximum number of donors to display.', 'give')}
/>
{/* TODO: Revert the field back once the backend for pagination is ready
<TextControl
label={__('Load More Button', 'give')}
value={loadMoreButtonText}
onChange={(value) => setAttributes({loadMoreButtonText: value})}
/>
*/}
</PanelBody>
</InspectorControls>
)}
</div>
);
}
16 changes: 16 additions & 0 deletions src/Campaigns/Blocks/CampaignDonors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {paragraph as icon} from '@wordpress/icons';
import schema from './block.json';
import Edit from './edit';

/**
* @unreleased
*/
const settings = {
icon,
edit: Edit,
};

export default {
schema,
settings,
};
61 changes: 61 additions & 0 deletions src/Campaigns/Blocks/CampaignDonors/render.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Give\Campaigns\Blocks\CampaignDonors;

use DateTime;
use Give\Campaigns\CampaignDonationQuery;
use Give\Campaigns\Models\Campaign;
use Give\Campaigns\Repositories\CampaignRepository;
use Give\Donations\ValueObjects\DonationMetaKeys;

/**
* @unreleased
*
* @var array $attributes
*/

if ( ! isset($attributes['campaignId'])) {
return;
}

/** @var Campaign $campaign */
$campaign = give(CampaignRepository::class)->getById($attributes['campaignId']);

if ( ! $campaign) {
return;
}

$sortBy = $attributes['sortBy'] ?? 'top-donors';
$query = (new CampaignDonationQuery($campaign))
->joinDonationMeta(DonationMetaKeys::DONOR_ID, 'donorIdMeta')
->joinDonationMeta(DonationMetaKeys::AMOUNT, 'amountMeta')
->leftJoin('give_donors', 'donorIdMeta.meta_value', 'donors.id', 'donors')
->limit($attributes['donorsPerPage'] ?? 5);

if ($sortBy === 'top-donors') {
$query->select(
'donorIdMeta.meta_value as id',
'SUM(amountMeta.meta_value) as amount',
'donors.name as name'
)
->groupBy('donorIdMeta.meta_value')
->orderBy('amount', 'DESC');
} else {
$query->joinDonationMeta(DonationMetaKeys::COMPANY, 'companyMeta')
->select(
'donation.ID as donationID',
'donorIdMeta.meta_value as id',
'companyMeta.meta_value as company',
'donation.post_date as date',
'amountMeta.meta_value as amount',
'donors.name as name'
)
->orderBy('donation.ID', 'DESC');
}

if ( ! $attributes['showAnonymous']) {
$query->joinDonationMeta(DonationMetaKeys::ANONYMOUS, 'anonymousMeta')
->where('anonymousMeta.meta_value', '0');
}

(new CampaignDonorsBlockViewModel($campaign, $query->getAll(), $attributes))->render();
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 3056b51

Please sign in to comment.