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

Earn: Move donations block to Jetpack Beta Blocks #16545

Merged
merged 10 commits into from
Jul 27, 2020
1 change: 1 addition & 0 deletions class.jetpack-plan.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class Jetpack_Plan {
),
'supports' => array(
'akismet',
'donations',
'recurring-payments',
),
),
Expand Down
64 changes: 64 additions & 0 deletions extensions/blocks/donations/attributes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* WordPress dependencies
*/
// eslint-disable-next-line wpcalypso/import-docblock
mmtr marked this conversation as resolved.
Show resolved Hide resolved
import { __ } from '@wordpress/i18n';

export default {
currency: {
type: 'string',
default: 'USD',
},
oneTimePlanId: {
type: 'number',
default: null,
},
monthlyPlanId: {
type: 'number',
default: null,
},
annuallyPlanId: {
type: 'number',
default: null,
},
showCustomAmount: {
type: 'boolean',
default: true,
},
oneTimeHeading: {
type: 'string',
default: __( 'Make a one-time donation', 'jetpack' ),
},
monthlyHeading: {
type: 'string',
default: __( 'Make a monthly donation', 'jetpack' ),
},
annualHeading: {
type: 'string',
default: __( 'Make a yearly donation', 'jetpack' ),
},
chooseAmountText: {
type: 'string',
default: __( 'Choose an amount (USD)', 'jetpack' ),
},
customAmountText: {
type: 'string',
default: __( 'Or enter a custom amount', 'jetpack' ),
},
extraText: {
type: 'string',
default: __( 'Your contribution is appreciated.', 'jetpack' ),
},
oneTimeButtonText: {
type: 'string',
default: __( 'Donate', 'jetpack' ),
},
monthlyButtonText: {
type: 'string',
default: __( 'Donate monthly', 'jetpack' ),
},
annualButtonText: {
type: 'string',
default: __( 'Donate yearly', 'jetpack' ),
},
};
11 changes: 11 additions & 0 deletions extensions/blocks/donations/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* WordPress dependencies
*/
// eslint-disable-next-line wpcalypso/import-docblock
import { createContext } from '@wordpress/element';

const Context = createContext( {
activeTab: 'one-time',
} );

export default Context;
42 changes: 42 additions & 0 deletions extensions/blocks/donations/controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* WordPress dependencies
*/
// eslint-disable-next-line wpcalypso/import-docblock
import { ExternalLink, PanelBody, ToggleControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { InspectorControls } from '@wordpress/block-editor';

const Controls = props => {
const { attributes, setAttributes, products, siteSlug } = props;
const { monthlyPlanId, annuallyPlanId, showCustomAmount } = attributes;
return (
<InspectorControls>
<PanelBody title={ __( 'Settings', 'jetpack' ) }>
<ToggleControl
checked={ !! monthlyPlanId }
onChange={ value =>
setAttributes( { monthlyPlanId: value ? products[ '1 month' ] : null } )
}
label={ __( 'Show monthly donations', 'jetpack' ) }
/>
<ToggleControl
checked={ !! annuallyPlanId }
onChange={ value =>
setAttributes( { annuallyPlanId: value ? products[ '1 year' ] : null } )
}
label={ __( 'Show annual donations', 'jetpack' ) }
/>
<ToggleControl
checked={ showCustomAmount }
onChange={ value => setAttributes( { showCustomAmount: value } ) }
label={ __( 'Show custom amount option', 'jetpack' ) }
/>
<ExternalLink href={ `https://wordpress.com/earn/payments/${ siteSlug }` }>
{ __( 'View donation earnings', 'jetpack' ) }
</ExternalLink>
</PanelBody>
</InspectorControls>
);
};

export default Controls;
44 changes: 44 additions & 0 deletions extensions/blocks/donations/donations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/**
* Donations Block.
*
* @since 8.x
*
* @package Jetpack
*/

namespace Automattic\Jetpack\Extensions\Donations;

use Jetpack_Gutenberg;

const FEATURE_NAME = 'donations';
const BLOCK_NAME = 'jetpack/' . FEATURE_NAME;

/**
* Registers the block for use in Gutenberg
* This is done via an action so that we can disable
* registration if we need to.
*/
function register_block() {
jetpack_register_block(
BLOCK_NAME,
array(
'render_callback' => __NAMESPACE__ . '\load_assets',
'plan_check' => true,
)
);
}
add_action( 'init', __NAMESPACE__ . '\register_block' );
mmtr marked this conversation as resolved.
Show resolved Hide resolved

/**
* Donations block registration/dependency declaration.
*
* @param array $attr Array containing the Donations block attributes.
* @param string $content String containing the Donations block content.
*
* @return string
*/
function load_assets( $attr, $content ) {
Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME );
return $content;
}
112 changes: 112 additions & 0 deletions extensions/blocks/donations/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* WordPress dependencies
*/
import { useState, useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import Tabs from './tabs';
import LoadingError from './loading-error';
import LoadingStatus from './loading-status';
import fetchDefaultProducts from './fetch-default-products';
import fetchStatus from './fetch-status';

const Edit = props => {
const { attributes, className } = props;
const { currency } = attributes;

const [ isLoading, setIsLoading ] = useState( true );
const [ loadingError, setLoadingError ] = useState( '' );
const [ shouldUpgrade, setShouldUpgrade ] = useState( false );
const [ stripeConnectUrl, setStripeConnectUrl ] = useState( false );
const [ products, setProducts ] = useState( [] );
const [ siteSlug, setSiteSlug ] = useState( '' );

const apiError = message => {
setLoadingError( message );
setIsLoading( false );
};

const filterProducts = productList =>
productList.reduce( ( filteredProducts, { id, currency: productCurrency, type, interval } ) => {
if ( productCurrency === currency && type === 'donation' ) {
filteredProducts[ interval ] = id;
}
return filteredProducts;
}, {} );

const hasRequiredProducts = productIdsPerInterval => {
const intervals = Object.keys( productIdsPerInterval );

return (
intervals.includes( 'one-time' ) &&
intervals.includes( '1 month' ) &&
intervals.includes( '1 year' )
);
};

const mapStatusToState = result => {
if ( ( ! result && typeof result !== 'object' ) || result.errors ) {
setLoadingError( __( 'Could not load data from WordPress.com.', 'jetpack' ) );
setIsLoading( false );
return;
}
setShouldUpgrade( result.should_upgrade_to_access_memberships );
setStripeConnectUrl( result.connect_url );
setSiteSlug( result.site_slug );

const filteredProducts = filterProducts( result.products );

if ( hasRequiredProducts( filteredProducts ) ) {
setProducts( filteredProducts );
setIsLoading( false );
return;
}

// Set fake products when plan should be upgraded or there is no connection to Stripe so users can still try the
// block in the editor.
if ( result.should_upgrade_to_access_memberships || result.connect_url ) {
setIsLoading( false );
setProducts( {
'one-time': -1,
'1 month': -1,
'1 year': -1,
} );
return;
}

// Only create products if we have the correct plan and stripe connection.
fetchDefaultProducts( currency ).then( defaultProducts => {
setIsLoading( false );
return setProducts( filterProducts( defaultProducts ) );
}, apiError );
};

useEffect( () => {
const updateData = () => fetchStatus( 'donation' ).then( mapStatusToState, apiError );
updateData();
}, [] );

if ( isLoading ) {
return <LoadingStatus className={ className } />;
}

if ( loadingError ) {
return <LoadingError className={ className } error={ loadingError } />;
}

return (
<Tabs
{ ...props }
className={ className }
products={ products }
shouldUpgrade={ shouldUpgrade }
siteSlug={ siteSlug }
stripeConnectUrl={ stripeConnectUrl }
/>
);
};

export default Edit;
7 changes: 7 additions & 0 deletions extensions/blocks/donations/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Internal dependencies
*/
import registerJetpackBlock from '../../shared/register-jetpack-block';
import { name, settings } from '.';

registerJetpackBlock( name, settings );
92 changes: 92 additions & 0 deletions extensions/blocks/donations/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
@import '../../shared/styles/gutenberg-base-styles.scss';

.wp-block-jetpack-donations {
.donations__container {
border: 1px solid $light-gray-700;

.donations__tabs {
display: flex;
border-bottom: 1px solid $light-gray-700;

.donations__tab {
font-weight: bold;
display: inline-block;
flex-grow: 1;
text-align: center;
font-size: 16px;
padding: 16px;
height: auto;
border-radius: 0;
border-left: 1px solid $light-gray-700;
background-color: $white;
color: $dark-gray-800;
box-shadow: none;

&:first-child {
border-left: none;
}

// Complex selector needed to override specificity.
&:not(:disabled):not([aria-disabled=true]):not(.is-secondary):not(.is-primary):not(.is-tertiary):not(.is-link):hover {
background-color: $light-gray-100;
box-shadow: none;
}

// Complex selector needed to override specificity.
&.is-active,
&.is-active:not(:disabled):not([aria-disabled=true]):not(.is-secondary):not(.is-primary):not(.is-tertiary):not(.is-link):hover {
background-color: $blue-wordpress-700;
box-shadow: none;
color: $white;
}
}
}

.donations__content {
padding: 0 24px;
}

.donations__amounts {
margin-top: 30px;
margin-bottom: 30px;

.donations__amount:not( .alignleft ):not( .alignright ) {
margin-top: 0;
margin-bottom: 0;
}
}

.donations__amount .wp-block-button__link {
background-color: $white;
color: $dark-gray-800;
border: 1px solid $light-gray-700;
}

.donations__custom-amount {
margin-bottom: 30px;
}

.donations__custom-amount .wp-block-button__link {
cursor: default;
}

.donations__custom-amount-placeholder {
margin-left: 8px;
color: $light-gray-700;
padding-right: 40px;
}

.donations__separator {
line-height: 8px;
height: 8px;
}

.donations__donate-button {
margin-bottom: 30px;
}
}

.jetpack-block-nudge {
max-width: none;
}
Comment on lines +88 to +91
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should we should be able to remove this now?

Suggested change
.jetpack-block-nudge {
max-width: none;
}

}
Loading