Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Campaign Goal Block #7702

Open
wants to merge 27 commits into
base: epic/campaigns
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f7b29b7
initial commit
alaca Jan 22, 2025
9c6d894
feature: render block
alaca Jan 23, 2025
088e26e
feature: add icon and btn
alaca Jan 23, 2025
673c59d
feature: add description and hide select component if default form is…
alaca Jan 23, 2025
76ead3f
chore: add unreleased tags
alaca Jan 23, 2025
572a377
refactor: move campaign forms fetching logic outside the useCampaign …
alaca Jan 29, 2025
f66d535
initial commit
alaca Jan 30, 2025
298b35b
refactor: remove unused attributes
alaca Jan 30, 2025
9385381
feature: add helper functions for displaying goal values and description
alaca Jan 30, 2025
7f1a040
refactor: add goalStats prop
alaca Jan 30, 2025
6859f65
refactor: use CampaignGoalData instead of CampaignDonationQuery for g…
alaca Jan 30, 2025
86ee2a8
refactor: use the new goalStats prop
alaca Jan 30, 2025
5034344
feature: add goalStats props
alaca Jan 30, 2025
069c39d
feature: render block
alaca Jan 31, 2025
15f0721
fix: missing campaign goal stats
alaca Feb 3, 2025
92e51e3
Merge branch 'refs/heads/epic/campaigns' into feature/campaign-goal-b…
alaca Feb 3, 2025
ca7d6c9
feature: add text control with goal description
alaca Feb 3, 2025
0c163b7
refactor: fix undefined campaign goalStats; use campaign method to ge…
alaca Feb 3, 2025
3a49194
Merge branch 'refs/heads/epic/campaigns' into feature/campaign-goal-b…
alaca Feb 3, 2025
e2cd894
feature: set language using navigator object
alaca Feb 3, 2025
0926bad
refactor: render block using ssr
alaca Feb 3, 2025
9b59101
Merge branch 'refs/heads/epic/campaigns' into feature/campaign-goal-b…
alaca Feb 7, 2025
04cbdd1
refactor: block settings
alaca Feb 7, 2025
4754280
refactor: everything
alaca Feb 10, 2025
0c409e5
refactor: remove leftover
alaca Feb 11, 2025
c88ad97
feature: format currency
alaca Feb 11, 2025
b1b67c0
refactor: load campaign options on both admin and frontend
alaca Feb 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/Campaigns/Blocks/CampaignGoal/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {render} from '@wordpress/element';
import useCampaign from '../shared/hooks/useCampaign';
import App from './app/index';

const BlockApp = ({campaignId}: { campaignId: number }) => {
const {campaign, hasResolved} = useCampaign(campaignId);

if (!hasResolved || !campaignId) {
return null;
}

return <App campaign={campaign} />;
}

/**
* @unreleased
*/
const nodeList = document.querySelectorAll('.give-campaigns-goalBlock-container');

if (nodeList) {
const containers = Array.from(nodeList);

containers.map((container: any) => {
return render(<BlockApp campaignId={container.dataset?.id} />, container);
});
}
34 changes: 34 additions & 0 deletions src/Campaigns/Blocks/CampaignGoal/app/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {__} from '@wordpress/i18n';
import {Campaign} from '@givewp/campaigns/admin/components/types';
import {getGoalDescription, getGoalFormattedValue} from '../utils';

import './styles.scss';

export default ({campaign}: { campaign: Campaign }) => {
return (
<div className="give-campaign-goal">
<div className="give-campaign-goal__container">
<div className="give-campaign-goal__container-item">
<span>{getGoalDescription(campaign.goalType)}</span>
<strong>
{getGoalFormattedValue(campaign.goalType, campaign.goalStats.actual)}
</strong>
</div>
<div className="give-campaign-goal__container-item">
<span>{__('Our goal', 'give')}</span>
<strong>
{getGoalFormattedValue(campaign.goalType, campaign.goal)}
</strong>
</div>
</div>
<div className="give-campaign-goal__progress-bar">
<div className="give-campaign-goal__progress-bar-container">
<div
className="give-campaign-goal__progress-bar-progress"
style={{width: `${campaign.goalStats.percentage}%`}}>
</div>
</div>
</div>
</div>
);
}
2 changes: 2 additions & 0 deletions src/Campaigns/Blocks/CampaignGoal/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@
},
"textdomain": "give",
"editorScript": "file:../../../../build/campaignGoalBlock.js",
alaca marked this conversation as resolved.
Show resolved Hide resolved
"viewScript": "file:../../../../build/campaignGoalBlockApp.js",
"style": "file:../../../../build/campaignGoalBlockApp.css",
"render": "file:./render.php"
}
26 changes: 4 additions & 22 deletions src/Campaigns/Blocks/CampaignGoal/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
import {__} from '@wordpress/i18n';
import {useSelect} from '@wordpress/data';
import {InspectorControls, useBlockProps} from '@wordpress/block-editor';
import ServerSideRender from '@wordpress/server-side-render';
import {BlockEditProps} from '@wordpress/blocks';
import {ExternalLink, PanelBody, TextControl} from '@wordpress/components';
import useCampaign from '../shared/hooks/useCampaign';
import CampaignGoalApp from './app/index';
import {CampaignSelector} from '../shared/components/CampaignSelector';

import './styles.scss';

const getGoalDescription = (goalType: string) => {
switch (goalType) {
case 'amount':
return __('Amount raised', 'give');
case 'donations':
return __('Number of donations', 'give');
case 'donors':
return __('Number of donors', 'give');
case 'amountFromSubscriptions':
return __('Recurring amount raised', 'give');
case 'subscriptions':
return __('Number of recurring donations', 'give');
case 'donorsFromSubscriptions':
return __('Number of recurring donors', 'give');
}
}
import {getGoalDescription} from './utils';

/**
* @unreleased
Expand All @@ -50,10 +32,10 @@ export default function Edit({attributes, setAttributes}: BlockEditProps<{
return (
<div {...blockProps}>
<CampaignSelector attributes={attributes} setAttributes={setAttributes}>
<ServerSideRender block="givewp/campaign-goal" attributes={attributes} />
<CampaignGoalApp campaign={campaign} />
</CampaignSelector>

{hasResolved && campaign?.id && (
{campaign?.id && (
<InspectorControls>
<PanelBody title={__('Settings', 'give')} initialOpen={true}>
<TextControl value={getGoalDescription(campaign.goalType)} onChange={null} disabled={true} />
Expand Down
51 changes: 1 addition & 50 deletions src/Campaigns/Blocks/CampaignGoal/render.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

use Give\Campaigns\Models\Campaign;
use Give\Campaigns\Repositories\CampaignRepository;
use Give\Campaigns\ValueObjects\CampaignGoalType;
use Give\Framework\Support\ValueObjects\Money;

/**
* @var array $attributes
Expand All @@ -17,53 +15,6 @@
return;
}

$stats = $campaign->getGoalStats();

$getGoalDescription = function(CampaignGoalType $goalType) {
$data = [
'amount' => __('Amount raised', 'give'),
'donations' => __('Number of donations', 'give'),
'donors' => __('Number of donors', 'give'),
'amountFromSubscriptions' => __('Recurring amount raised', 'give'),
'subscriptions' => __('Number of recurring donations', 'give'),
'donorsFromSubscriptions' => __('Number of recurring donors', 'give'),
];

return $data[$goalType->getvalue()];
};

$getGoalFormattedValue = function($goalType, $value) {
switch ($goalType) {
case 'amount':
case 'amountFromSubscriptions':
$amount = Money::fromDecimal($value, give_get_currency());
return $amount->formatToLocale();
default:
return $value;
}
};

?>

<div class="give-campaign-goal">
<div class="give-campaign-goal__container">
<div class="give-campaign-goal__container-item">
<span><?= $getGoalDescription($campaign->goalType); ?></span>
<strong>
<?= $getGoalFormattedValue($campaign->goalType, $stats['actual']); ?>
</strong>
</div>
<div class="give-campaign-goal__container-item">
<span><?= esc_html__('Our goal', 'give'); ?></span>
<strong><?= $getGoalFormattedValue($campaign->goalType, $campaign->goal); ?></strong>
</div>
</div>
<div class="give-campaign-goal__progress-bar">
<div class="give-campaign-goal__progress-bar-container">
<div class="give-campaign-goal__progress-bar-progress"
style="width: <?= $stats['percentage']; ?>%">
</div>
</div>
</div>
</div>

<div class="give-campaigns-goalBlock-container" data-id="<?= $campaign->id; ?>"></div>
29 changes: 29 additions & 0 deletions src/Campaigns/Blocks/CampaignGoal/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {__} from '@wordpress/i18n';

export const getGoalDescription = (goalType: string) => {
switch (goalType) {
case 'amount':
return __('Amount raised', 'give');
case 'donations':
return __('Number of donations', 'give');
case 'donors':
return __('Number of donors', 'give');
case 'amountFromSubscriptions':
return __('Recurring amount raised', 'give');
case 'subscriptions':
return __('Number of recurring donations', 'give');
case 'donorsFromSubscriptions':
return __('Number of recurring donors', 'give');
}
}


export const getGoalFormattedValue = (goalType: string, value: number) => {
switch (goalType) {
case 'amount':
case 'amountFromSubscriptions':

default:
return value;
}
}
1 change: 1 addition & 0 deletions wordpress-scripts-webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ module.exports = {
campaignBlocks: srcPath('Campaigns/Blocks/blocks.ts'),
campaignDonationsBlockApp: srcPath('Campaigns/Blocks/CampaignDonations/app.tsx'),
campaignDonorsBlockApp: srcPath('Campaigns/Blocks/CampaignDonors/app.tsx'),
campaignGoalBlockApp: srcPath('Campaigns/Blocks/CampaignGoal/app.tsx'),
},
};

Expand Down
Loading