From 669247f924a0692f0c5ef478d0f7f1b254e6a620 Mon Sep 17 00:00:00 2001 From: Paulo Iankoski Date: Fri, 31 Jan 2025 08:31:16 -0300 Subject: [PATCH 1/6] feature: add Campaign Donations block --- .../Blocks/CampaignDonationsBlock/block.json | 48 ++++ .../Blocks/CampaignDonationsBlock/edit.tsx | 98 +++++++ .../Blocks/CampaignDonationsBlock/index.ts | 14 + .../Blocks/CampaignDonationsBlock/render.php | 247 ++++++++++++++++++ .../Blocks/CampaignDonationsBlock/style.css | 190 ++++++++++++++ src/Campaigns/Blocks/blocks.ts | 3 +- 6 files changed, 599 insertions(+), 1 deletion(-) create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/block.json create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/edit.tsx create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/index.ts create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/render.php create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/style.css diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/block.json b/src/Campaigns/Blocks/CampaignDonationsBlock/block.json new file mode 100644 index 0000000000..e188c2e76e --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/block.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "givewp/campaign-donations-block", + "version": "1.0.0", + "title": "Campaign Donations", + "category": "give", + "description": "Display all the donations associated with a campaign.", + "attributes": { + "campaignId": { + "type": "integer" + }, + "showAnonymous": { + "type": "boolean", + "default": true + }, + "showIcon": { + "type": "boolean", + "default": true + }, + "showButton": { + "type": "boolean", + "default": true + }, + "donateButtonText": { + "type": "string", + "default": "Donate" + }, + "sortBy": { + "type": "string", + "default": "top-donations" + }, + "donationsPerPage": { + "type": "number", + "default": 5 + }, + "loadMoreButtonText": { + "type": "string", + "default": "Load more" + } + }, + "supports": { + "className": true + }, + "textdomain": "give", + "render": "file:./render.php", + "style": "givewp-CampaignDonationsBlock-style" +} diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/edit.tsx b/src/Campaigns/Blocks/CampaignDonationsBlock/edit.tsx new file mode 100644 index 0000000000..0cb486a486 --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/edit.tsx @@ -0,0 +1,98 @@ +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; + showIcon: boolean; + showButton: boolean; + donateButtonText: string; + sortBy: string; + donationsPerPage: number; + loadMoreButtonText: string; +}>) { + const blockProps = useBlockProps(); + const {campaign, hasResolved} = useCampaign(attributes.campaignId); + + const {showAnonymous, showIcon, showButton, donateButtonText, sortBy, donationsPerPage, loadMoreButtonText} = + attributes; + + return ( +
+ + + + + {hasResolved && campaign?.id && ( + + + setAttributes({showAnonymous: value})} + /> + setAttributes({showIcon: value})} + /> + setAttributes({showButton: value})} + /> + setAttributes({donateButtonText: value})} + help={__('This shows on the header', 'give')} + /> + + + + setAttributes({sortBy: value})} + help={__('The order donations 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 */} + setAttributes({donationsPerPage: parseInt(value)})} + help={__('The maximum number of donations to display.', 'give')} + /> + {/* TODO: Revert the field back once the backend for pagination is ready + setAttributes({loadMoreButtonText: value})} + /> + */} + + + )} +
+ ); +} diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/index.ts b/src/Campaigns/Blocks/CampaignDonationsBlock/index.ts new file mode 100644 index 0000000000..1468f6677c --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/index.ts @@ -0,0 +1,14 @@ +import {paragraph as icon} from '@wordpress/icons'; +import metadata from './block.json'; +import Edit from './edit'; +import initBlock from '../shared/utils/init-block'; + +const {name} = metadata; + +export {metadata, name}; +export const settings = { + icon, + edit: Edit, +}; + +export const init = () => initBlock({name, metadata, settings}); diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/render.php b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php new file mode 100644 index 0000000000..066a360974 --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php @@ -0,0 +1,247 @@ +attributes = $attributes; + $this->campaign = $this->fetchCampaign(); + } + + /** + * @unreleased + */ + private function fetchCampaign(): ?Campaign + { + if ( ! isset($this->attributes['campaignId'])) { + return null; + } + + return give(CampaignRepository::class)->getById($this->attributes['campaignId']); + } + + /** + * @unreleased + */ + public function render(): void + { + if ( ! $this->campaign) { + return; + } + + $query = $this->buildDonationsQuery(); + $donations = $this->formatDonationsData($query->getAll()); + $this->renderBlockHtml($donations); + } + + /** + * @unreleased + */ + private function buildDonationsQuery(): CampaignDonationQuery + { + $sortBy = $this->attributes['sortBy'] ?? 'top-donations'; + $query = (new CampaignDonationQuery($this->campaign)) + ->select( + 'donation.ID as id', + 'donorIdMeta.meta_value as donorId', + 'amountMeta.meta_value as amount', + 'donation.post_date as date', + 'donors.name as donorName' + ) + ->joinDonationMeta(DonationMetaKeys::DONOR_ID, 'donorIdMeta') + ->joinDonationMeta(DonationMetaKeys::AMOUNT, 'amountMeta') + ->leftJoin('give_donors', 'donorIdMeta.meta_value', 'donors.id', 'donors') + ->orderBy($sortBy === 'top-donations' ? 'amount' : 'donation.ID', 'DESC') + ->limit($this->attributes['donationsPerPage'] ?? 5); + + if ( ! $this->attributes['showAnonymous']) { + $query->joinDonationMeta(DonationMetaKeys::ANONYMOUS, 'anonymousMeta') + ->where('anonymousMeta.meta_value', '0'); + } + + return $query; + } + + /** + * @unreleased + */ + private function formatDonationsData(array $donations): array + { + return array_map(static function ($entry) { + $entry->date = human_time_diff(strtotime($entry->date)); + $entry->amount = Money::fromDecimal($entry->amount, give_get_currency()); + + return $entry; + }, $donations); + } + + /** + * @unreleased + */ + private function renderBlockHtml($donations): void + { + $sortBy = $this->attributes['sortBy'] ?? 'top-donations'; + $blockTitle = $sortBy === 'top-donations' ? __('Top Donations', 'give') : __( + 'Recent Donations', + 'give' + ); + $donateButtonText = $this->attributes['donateButtonText'] ?? __('Donate', 'give'); + + $blockInlineStyles = sprintf( + '--givewp-primary-color: %s; --givewp-secondary-color: %s;', + esc_attr('#0b72d9'), + esc_attr('#27ae60') + ); + ?> +
'givewp-campaign-donations-block'])); ?> + style=""> +
+

+ attributes['showButton'] && ! empty($donations)) : ?> +
+ $this->campaign->defaultFormId, + 'openFormButton' => $donateButtonText, + 'formFormat' => 'modal', + ]; + + echo (new BlockRenderController())->render($params); + ?> +
+ +
+ + +
+

+ +

+

+ +

+ + + + + + attributes['showButton']) : ?> +
+ $this->campaign->defaultFormId, + 'openFormButton' => __('Be the first', 'give'), + 'formFormat' => 'modal', + ]; + + echo (new BlockRenderController())->render($params); + ?> +
+ +
+ + + +
+ render(); diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/style.css b/src/Campaigns/Blocks/CampaignDonationsBlock/style.css new file mode 100644 index 0000000000..cdf17aae11 --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/style.css @@ -0,0 +1,190 @@ +.givewp-campaign-donations-block { + padding: 1.5rem 0; +} + +.givewp-campaign-donations-block * { + font-family: 'Inter', sans-serif; +} + +.givewp-campaign-donations-block__header { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 0.5rem; +} + +.givewp-campaign-donations-block__title { + color: var(--givewp-neutral-900); + font-size: 1.125rem; + font-weight: 600; + line-height: 1.56; + margin: 0; +} + +:is(.givewp-campaign-donations-block__donate-button, .givewp-campaign-donations-block__empty-button) button.givewp-donation-form-modal__open { + background: none; + border-radius: 0.5rem; + border: 1px solid var(--givewp-primary-color); + color: var(--givewp-primary-color) !important; + font-size: 0.875rem; + font-weight: 600; + line-height: 1.43; + padding: 0.25rem 1rem !important; +} + +:is(.givewp-campaign-donations-block__donate-button, .givewp-campaign-donations-block__empty-button) button.givewp-donation-form-modal__open:hover { + background: var(--givewp-primary-color); + color: var(--givewp-shades-white) !important; +} + +.givewp-campaign-donations-block__donations { + display: grid; + gap: 0.5rem; + margin: 0; + padding: 0; +} + +.givewp-campaign-donations-block__donation { + align-items: center; + background-color: var(--givewp-shades-white); + border-radius: 0.5rem; + border: 1px solid var(--givewp-neutral-50); + display: flex; + gap: 0.75rem; + padding: 1rem; +} + +.givewp-campaign-donations-block__donation-icon { + display: flex; + align-items: center; +} + +.givewp-campaign-donations-block__donation-icon img { + border-radius: 100%; + height: 2.5rem; + object-fit: cover; + width: 2.5rem; +} + +.givewp-campaign-donations-block__donation-info { + display: flex; + flex-direction: column; + justify-content: center; + row-gap: 0.25rem; +} + +.givewp-campaign-donations-block__donation-description { + color: var(--givewp-neutral-500); + font-size: 1rem; + font-weight: 500; + line-height: 1.5; + margin: 0; +} + +.givewp-campaign-donations-block__donation-description strong { + color: var(--givewp-neutral-700); + font-weight: 600; +} + +.givewp-campaign-donations-block__donation-date { + align-items: center; + color: var(--givewp-neutral-400); + display: flex; + font-size: 0.875rem; + font-weight: 500; + line-height: 1.43; +} + +.givewp-campaign-donations-block__donation-ribbon { + align-items: center; + border-radius: 100%; + color: #1F2937; + display: flex; + height: 1.25rem; + justify-content: center; + margin-left: auto; + width: 1.25rem; +} + +.givewp-campaign-donations-block__donation-ribbon[data-position="1"] { + background-color: #ffd700; +} + +.givewp-campaign-donations-block__donation-ribbon[data-position="2"] { + background-color: #c0c0c0; +} + +.givewp-campaign-donations-block__donation-ribbon[data-position="3"] { + background-color: #cd7f32; + color: #fffaf2; +} + +.givewp-campaign-donations-block__donation-amount { + color: var(--givewp-neutral-700); + font-size: 1.125rem; + font-weight: 600; + line-height: 1.56; + margin-left: auto; +} + +.givewp-campaign-donations-block__footer { + display: flex; + justify-content: center; + margin-top: 0.5rem; +} + +.givewp-campaign-donations-block__load-more-button { + background: none; + border-radius: 0.5rem; + border: 1px solid var(--givewp-primary-color); + color: var(--givewp-primary-color); + font-size: 0.875rem; + font-weight: 600; + line-height: 1.43; + padding: 0.25rem 1rem; +} + +.givewp-campaign-donations-block__load-more-button:hover { + background: var(--givewp-primary-color); + color: var(--givewp-shades-white); +} + +.givewp-campaign-donations-block__empty-state { + align-items: center; + background-color: var(--givewp-shades-white); + border-radius: 0.5rem; + border: 1px solid var(--givewp-neutral-50); + display: flex; + flex-direction: column; + padding: 1.5rem; +} + +.givewp-campaign-donations-block__empty-title { + color: var(--givewp-neutral-700); + font-size: 1rem; + font-weight: 500; + line-height: 1.5; + margin: 0; +} + +.givewp-campaign-donations-block__empty-description { + color: var(--givewp-neutral-700); + font-size: 0.875rem; + line-height: 1.43; + margin: 0.25rem 0 0; +} + +.givewp-campaign-donations-block__empty-icon { + color: var(--givewp-secondary-color); + margin-bottom: 0.875rem; + order: -1; +} + +.givewp-campaign-donations-block__empty-button { + margin-top: 0.875rem; +} + +.givewp-campaign-donations-block__empty-button button.givewp-donation-form-modal__open { + border-radius: 0.25rem; + padding: 0.5rem 1rem !important; +} diff --git a/src/Campaigns/Blocks/blocks.ts b/src/Campaigns/Blocks/blocks.ts index 21f8f96575..87e4ff7c8d 100644 --- a/src/Campaigns/Blocks/blocks.ts +++ b/src/Campaigns/Blocks/blocks.ts @@ -1,8 +1,9 @@ import * as campaignTitleBlock from './CampaignTitleBlock'; import * as campaignDonorsBlock from './CampaignDonorsBlock'; +import * as campaignDonationsBock from './CampaignDonationsBlock'; const getAllBlocks = () => { - return [campaignTitleBlock, campaignDonorsBlock]; + return [campaignTitleBlock, campaignDonorsBlock, campaignDonationsBock]; }; getAllBlocks().forEach((block) => { From 667d4f666d6939a5394398b2a7ff6c427b205516 Mon Sep 17 00:00:00 2001 From: Paulo Iankoski Date: Fri, 31 Jan 2025 09:41:43 -0300 Subject: [PATCH 2/6] refactor: replace empty state icon --- src/Campaigns/Blocks/CampaignDonationsBlock/render.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/render.php b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php index 066a360974..8c9c09e0e3 100644 --- a/src/Campaigns/Blocks/CampaignDonationsBlock/render.php +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php @@ -145,7 +145,7 @@ private function renderBlockHtml($donations): void + if (empty($donations) || 1 === 1) : ?>

+ From 9392c1085bb153535a92e0fae8d0c3ce9b478e47 Mon Sep 17 00:00:00 2001 From: alaca Date: Fri, 31 Jan 2025 19:49:42 +0100 Subject: [PATCH 3/6] refactor: pair programming - use View class; add Campaign --- .../CampaignDonationsBlockViewModel.php | 100 +++++++ .../Blocks/CampaignDonationsBlock/render.php | 246 +----------------- .../resources/views/render.php | 141 ++++++++++ 3 files changed, 244 insertions(+), 243 deletions(-) create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php b/src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php new file mode 100644 index 0000000000..4e1d6f89a2 --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php @@ -0,0 +1,100 @@ +attributes = $attributes; + $this->campaign = $this->fetchCampaign(); + } + + /** + * @unreleased + */ + private function fetchCampaign(): ?Campaign + { + if ( ! isset($this->attributes['campaignId'])) { + return null; + } + + return give(CampaignRepository::class)->getById($this->attributes['campaignId']); + } + + /** + * @unreleased + */ + public function render(): void + { + if ( ! $this->campaign) { + return; + } + + $query = $this->buildDonationsQuery(); + $donations = $this->formatDonationsData($query->getAll()); + + View::render('Campaigns/Blocks/CampaignDonationsBlock.render', ['donations' => $donations]); + } + + /** + * @unreleased + */ + private function buildDonationsQuery(): CampaignDonationQuery + { + $sortBy = $this->attributes['sortBy'] ?? 'top-donations'; + $query = (new CampaignDonationQuery($this->campaign)) + ->select( + 'donation.ID as id', + 'donorIdMeta.meta_value as donorId', + 'amountMeta.meta_value as amount', + 'donation.post_date as date', + 'donors.name as donorName' + ) + ->joinDonationMeta(DonationMetaKeys::DONOR_ID, 'donorIdMeta') + ->joinDonationMeta(DonationMetaKeys::AMOUNT, 'amountMeta') + ->leftJoin('give_donors', 'donorIdMeta.meta_value', 'donors.id', 'donors') + ->orderBy($sortBy === 'top-donations' ? 'amount' : 'donation.ID', 'DESC') + ->limit($this->attributes['donationsPerPage'] ?? 5); + + if ( ! $this->attributes['showAnonymous']) { + $query->joinDonationMeta(DonationMetaKeys::ANONYMOUS, 'anonymousMeta') + ->where('anonymousMeta.meta_value', '0'); + } + + return $query; + } + + /** + * @unreleased + */ + private function formatDonationsData(array $donations): array + { + return array_map(static function ($entry) { + $entry->date = human_time_diff(strtotime($entry->date)); + $entry->amount = Money::fromDecimal($entry->amount, give_get_currency()); + + return $entry; + }, $donations); + } +} diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/render.php b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php index 8c9c09e0e3..d161fa41bb 100644 --- a/src/Campaigns/Blocks/CampaignDonationsBlock/render.php +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php @@ -2,250 +2,10 @@ namespace Give\Campaigns\Blocks\CampaignDonationsBlock; -use Give\Campaigns\CampaignDonationQuery; -use Give\Campaigns\Models\Campaign; -use Give\Campaigns\Repositories\CampaignRepository; -use Give\DonationForms\Blocks\DonationFormBlock\Controllers\BlockRenderController; -use Give\Donations\ValueObjects\DonationMetaKeys; -use Give\Framework\Support\ValueObjects\Money; - /** * @unreleased + * + * @var array $attributes */ -if ( ! class_exists(CampaignDonationsBlockRenderer::class)) { - class CampaignDonationsBlockRenderer - { - /** - * @var Campaign $campaign - */ - private $campaign; - - /** - * @var array $attributes - */ - private $attributes; - - /** - * @unreleased - */ - public function __construct($attributes) - { - $this->attributes = $attributes; - $this->campaign = $this->fetchCampaign(); - } - - /** - * @unreleased - */ - private function fetchCampaign(): ?Campaign - { - if ( ! isset($this->attributes['campaignId'])) { - return null; - } - - return give(CampaignRepository::class)->getById($this->attributes['campaignId']); - } - - /** - * @unreleased - */ - public function render(): void - { - if ( ! $this->campaign) { - return; - } - - $query = $this->buildDonationsQuery(); - $donations = $this->formatDonationsData($query->getAll()); - $this->renderBlockHtml($donations); - } - - /** - * @unreleased - */ - private function buildDonationsQuery(): CampaignDonationQuery - { - $sortBy = $this->attributes['sortBy'] ?? 'top-donations'; - $query = (new CampaignDonationQuery($this->campaign)) - ->select( - 'donation.ID as id', - 'donorIdMeta.meta_value as donorId', - 'amountMeta.meta_value as amount', - 'donation.post_date as date', - 'donors.name as donorName' - ) - ->joinDonationMeta(DonationMetaKeys::DONOR_ID, 'donorIdMeta') - ->joinDonationMeta(DonationMetaKeys::AMOUNT, 'amountMeta') - ->leftJoin('give_donors', 'donorIdMeta.meta_value', 'donors.id', 'donors') - ->orderBy($sortBy === 'top-donations' ? 'amount' : 'donation.ID', 'DESC') - ->limit($this->attributes['donationsPerPage'] ?? 5); - - if ( ! $this->attributes['showAnonymous']) { - $query->joinDonationMeta(DonationMetaKeys::ANONYMOUS, 'anonymousMeta') - ->where('anonymousMeta.meta_value', '0'); - } - - return $query; - } - - /** - * @unreleased - */ - private function formatDonationsData(array $donations): array - { - return array_map(static function ($entry) { - $entry->date = human_time_diff(strtotime($entry->date)); - $entry->amount = Money::fromDecimal($entry->amount, give_get_currency()); - - return $entry; - }, $donations); - } - - /** - * @unreleased - */ - private function renderBlockHtml($donations): void - { - $sortBy = $this->attributes['sortBy'] ?? 'top-donations'; - $blockTitle = $sortBy === 'top-donations' ? __('Top Donations', 'give') : __( - 'Recent Donations', - 'give' - ); - $donateButtonText = $this->attributes['donateButtonText'] ?? __('Donate', 'give'); - - $blockInlineStyles = sprintf( - '--givewp-primary-color: %s; --givewp-secondary-color: %s;', - esc_attr('#0b72d9'), - esc_attr('#27ae60') - ); - ?> -
'givewp-campaign-donations-block'])); ?> - style=""> -
-

- attributes['showButton'] && ! empty($donations)) : ?> -
- $this->campaign->defaultFormId, - 'openFormButton' => $donateButtonText, - 'formFormat' => 'modal', - ]; - - echo (new BlockRenderController())->render($params); - ?> -
- -
- - -
-

- -

-

- -

- - - - - - - attributes['showButton']) : ?> -
- $this->campaign->defaultFormId, - 'openFormButton' => __('Be the first', 'give'), - 'formFormat' => 'modal', - ]; - - echo (new BlockRenderController())->render($params); - ?> -
- -
- -
    - $donation) : ?> -
  • - attributes['showIcon']) : ?> -
    - <?php
-                                            _e('Donation icon', 'give'); ?> -
    - - -
    -
    - ' . esc_html($donation->donorName) . '', - '' . esc_html($donation->amount->formatToLocale()) . '' - ); - ?> -
    - - date - ) - ); ?> -
    - - -
    - - - -
    - -
  • - -
- -
- render(); +(new CampaignDonationsBlockViewModel($attributes))->render(); diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php new file mode 100644 index 0000000000..30044c0465 --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php @@ -0,0 +1,141 @@ +attributes['sortBy'] ?? 'top-donations'; +$blockTitle = $sortBy === 'top-donations' ? __('Top Donations', 'give') : __( + 'Recent Donations', + 'give' +); +$donateButtonText = $this->attributes['donateButtonText'] ?? __('Donate', 'give'); + +$blockInlineStyles = sprintf( + '--givewp-primary-color: %s; --givewp-secondary-color: %s;', + esc_attr('#0b72d9'), + esc_attr('#27ae60') +); +?> +
'givewp-campaign-donations-block'])); ?> + style=""> +
+

+ attributes['showButton'] && ! empty($donations)) : ?> +
+ $this->campaign->defaultFormId, + 'openFormButton' => $donateButtonText, + 'formFormat' => 'modal', + ]; + + echo (new BlockRenderController())->render($params); + ?> +
+ +
+ + +
+

+ +

+

+ +

+ + + + + + + attributes['showButton']) : ?> +
+ $this->campaign->defaultFormId, + 'openFormButton' => __('Be the first', 'give'), + 'formFormat' => 'modal', + ]; + + echo (new BlockRenderController())->render($params); + ?> +
+ +
+ +
    + $donation) : ?> +
  • + attributes['showIcon']) : ?> +
    + <?php
+                                _e('Donation icon', 'give'); ?> +
    + + +
    +
    + ' . esc_html($donation->donorName) . '', + '' . esc_html($donation->amount->formatToLocale()) . '' + ); + ?> +
    + + date + ) + ); ?> +
    + + +
    + + + +
    + +
  • + +
+ +
From b8dc3b75dc41b65001ac7195b3502b80aa705ddb Mon Sep 17 00:00:00 2001 From: alaca Date: Fri, 31 Jan 2025 20:12:43 +0100 Subject: [PATCH 4/6] refactor: pair programming - use View class; add Campaign --- .../CampaignDonationsBlockViewModel.php | 65 +++++-------------- .../Blocks/CampaignDonationsBlock/render.php | 38 ++++++++++- .../resources/views/render.php | 40 +++++------- .../Blocks/CampaignTitleBlock/render.php | 9 --- 4 files changed, 70 insertions(+), 82 deletions(-) diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php b/src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php index 4e1d6f89a2..ac2e03b115 100644 --- a/src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/CampaignDonationsBlockViewModel.php @@ -4,8 +4,6 @@ use Give\Campaigns\CampaignDonationQuery; use Give\Campaigns\Models\Campaign; -use Give\Campaigns\Repositories\CampaignRepository; -use Give\Donations\ValueObjects\DonationMetaKeys; use Give\Framework\Support\ValueObjects\Money; use Give\Framework\Views\View; @@ -20,26 +18,19 @@ class CampaignDonationsBlockViewModel * @var array $attributes */ private $attributes; - /** - * @unreleased + * @var CampaignDonationQuery */ - public function __construct($attributes) - { - $this->attributes = $attributes; - $this->campaign = $this->fetchCampaign(); - } + private $donations; /** * @unreleased */ - private function fetchCampaign(): ?Campaign + public function __construct(Campaign $campaign, array $donations, array $attributes) { - if ( ! isset($this->attributes['campaignId'])) { - return null; - } - - return give(CampaignRepository::class)->getById($this->attributes['campaignId']); + $this->attributes = $attributes; + $this->campaign = $campaign; + $this->donations = $donations; } /** @@ -47,43 +38,17 @@ private function fetchCampaign(): ?Campaign */ public function render(): void { - if ( ! $this->campaign) { - return; - } - - $query = $this->buildDonationsQuery(); - $donations = $this->formatDonationsData($query->getAll()); - - View::render('Campaigns/Blocks/CampaignDonationsBlock.render', ['donations' => $donations]); + View::render('Campaigns/Blocks/CampaignDonationsBlock.render', [ + 'campaign' => $this->campaign, + 'donations' => $this->formatDonationsData($this->donations), + 'params' => [ + 'formId' => $this->campaign->defaultFormId, + 'openFormButton' => $this->attributes['donateButtonText'], + 'formFormat' => 'modal', + ], + ]); } - /** - * @unreleased - */ - private function buildDonationsQuery(): CampaignDonationQuery - { - $sortBy = $this->attributes['sortBy'] ?? 'top-donations'; - $query = (new CampaignDonationQuery($this->campaign)) - ->select( - 'donation.ID as id', - 'donorIdMeta.meta_value as donorId', - 'amountMeta.meta_value as amount', - 'donation.post_date as date', - 'donors.name as donorName' - ) - ->joinDonationMeta(DonationMetaKeys::DONOR_ID, 'donorIdMeta') - ->joinDonationMeta(DonationMetaKeys::AMOUNT, 'amountMeta') - ->leftJoin('give_donors', 'donorIdMeta.meta_value', 'donors.id', 'donors') - ->orderBy($sortBy === 'top-donations' ? 'amount' : 'donation.ID', 'DESC') - ->limit($this->attributes['donationsPerPage'] ?? 5); - - if ( ! $this->attributes['showAnonymous']) { - $query->joinDonationMeta(DonationMetaKeys::ANONYMOUS, 'anonymousMeta') - ->where('anonymousMeta.meta_value', '0'); - } - - return $query; - } /** * @unreleased diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/render.php b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php index d161fa41bb..965d0239ae 100644 --- a/src/Campaigns/Blocks/CampaignDonationsBlock/render.php +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/render.php @@ -2,10 +2,46 @@ namespace Give\Campaigns\Blocks\CampaignDonationsBlock; +use Give\Campaigns\CampaignDonationQuery; +use Give\Campaigns\Models\Campaign; +use Give\Campaigns\Repositories\CampaignRepository; +use Give\Donations\ValueObjects\DonationMetaKeys; + /** * @unreleased * * @var array $attributes */ -(new CampaignDonationsBlockViewModel($attributes))->render(); +if ( ! isset($attributes['campaignId'])) { + return; +} + +/** @var Campaign $campaign */ +$campaign = give(CampaignRepository::class)->getById($attributes['campaignId']); + +if ( ! $campaign) { + return; +} + +$sortBy = $attributes['sortBy'] ?? 'top-donations'; +$query = (new CampaignDonationQuery($campaign)) + ->select( + 'donation.ID as id', + 'donorIdMeta.meta_value as donorId', + 'amountMeta.meta_value as amount', + 'donation.post_date as date', + 'donors.name as donorName' + ) + ->joinDonationMeta(DonationMetaKeys::DONOR_ID, 'donorIdMeta') + ->joinDonationMeta(DonationMetaKeys::AMOUNT, 'amountMeta') + ->leftJoin('give_donors', 'donorIdMeta.meta_value', 'donors.id', 'donors') + ->orderBy($sortBy === 'top-donations' ? 'amount' : 'donation.ID', 'DESC') + ->limit($attributes['donationsPerPage'] ?? 5); + +if ( ! $attributes['showAnonymous']) { + $query->joinDonationMeta(DonationMetaKeys::ANONYMOUS, 'anonymousMeta') + ->where('anonymousMeta.meta_value', '0'); +} + +(new CampaignDonationsBlockViewModel($campaign, $query->getAll(), $attributes))->render(); diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php index 30044c0465..0fcbee9f83 100644 --- a/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php @@ -1,13 +1,17 @@ attributes['sortBy'] ?? 'top-donations'; -$blockTitle = $sortBy === 'top-donations' ? __('Top Donations', 'give') : __( - 'Recent Donations', - 'give' -); -$donateButtonText = $this->attributes['donateButtonText'] ?? __('Donate', 'give'); +/** + * @var Campaign $campaign + * @var array $attributes + * @var array $params + */ + +$sortBy = $attributes['sortBy'] ?? 'top-donations'; +$blockTitle = $sortBy === 'top-donations' ? __('Top Donations', 'give') : __('Recent Donations', 'give'); +$donateButtonText = $attributes['donateButtonText'] ?? __('Donate', 'give'); $blockInlineStyles = sprintf( '--givewp-primary-color: %s; --givewp-secondary-color: %s;', @@ -24,32 +28,24 @@

attributes['showButton'] && ! empty($donations)) : ?> + if ($attributes['showButton'] && ! empty($donations)) : ?>
- $this->campaign->defaultFormId, - 'openFormButton' => $donateButtonText, - 'formFormat' => 'modal', - ]; - - echo (new BlockRenderController())->render($params); - ?> + render($params); ?>

+ if (empty($donations)) : ?>

+ esc_html_e('Every campaign starts with one donation.', 'give'); ?>

+ esc_html_e('Be the one to mate it happen!', 'give'); ?>

attributes['showButton']) : ?> + if ($attributes['showButton']) : ?>
$this->campaign->defaultFormId, + 'formId' => $campaign->defaultFormId, 'openFormButton' => __('Be the first', 'give'), 'formFormat' => 'modal', ]; @@ -87,7 +83,7 @@ foreach ($donations as $key => $donation) : ?>
  • attributes['showIcon']) : ?> + if ($attributes['showIcon']) : ?>
    - render($params); ?> + render([ + 'formId' => $campaign->defaultFormId, + 'openFormButton' => $attributes['donateButtonText'], + 'formFormat' => 'modal', + ]); ?>
    @@ -64,13 +68,11 @@ if ($attributes['showButton']) : ?>
    render([ 'formId' => $campaign->defaultFormId, 'openFormButton' => __('Be the first', 'give'), 'formFormat' => 'modal', - ]; - - echo (new BlockRenderController())->render($params); + ]); ?>
    Date: Fri, 31 Jan 2025 16:40:59 -0300 Subject: [PATCH 6/6] refactor: extract icons from the template --- .../resources/icons/empty-state.svg | 11 +++++++++ .../resources/icons/ribbon.svg | 6 +++++ .../resources/views/render.php | 23 +++++-------------- 3 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/empty-state.svg create mode 100644 src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/ribbon.svg diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/empty-state.svg b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/empty-state.svg new file mode 100644 index 0000000000..97c9d126fe --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/empty-state.svg @@ -0,0 +1,11 @@ + + + + diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/ribbon.svg b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/ribbon.svg new file mode 100644 index 0000000000..5b8803f0be --- /dev/null +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/icons/ribbon.svg @@ -0,0 +1,6 @@ + + + diff --git a/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php index 4518db6812..bc6f530c3c 100644 --- a/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php +++ b/src/Campaigns/Blocks/CampaignDonationsBlock/resources/views/render.php @@ -52,17 +52,10 @@ esc_html_e('Be the one to mate it happen!', 'give'); ?>

    - - - - +
    + +
    @@ -121,12 +114,8 @@ if ($sortBy === 'top-donations' && $key < 3) : ?>
    - - - +