mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-04 08:47:23 +08:00
Merge branch 'PCP-3398-critical-error-when-changing-subscription-payment-method-to-advanced-card-processing' into PCP-4110-incorrect-subscription-cancellation-handling-with-pay-pal-subscriptions
This commit is contained in:
commit
13f17410ea
229 changed files with 6074 additions and 3425 deletions
|
@ -80,10 +80,19 @@ use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\ConnectBearer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\EnvironmentConfig;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
|
||||
return array(
|
||||
'api.host' => function( ContainerInterface $container ) : string {
|
||||
return PAYPAL_API_URL;
|
||||
'api.host' => static function( ContainerInterface $container ) : string {
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
assert( $environment instanceof Environment );
|
||||
|
||||
if ( $environment->is_sandbox() ) {
|
||||
return (string) $container->get( 'api.sandbox-host' );
|
||||
}
|
||||
|
||||
return (string) $container->get( 'api.production-host' );
|
||||
},
|
||||
'api.paypal-host' => function( ContainerInterface $container ) : string {
|
||||
return PAYPAL_API_URL;
|
||||
|
@ -116,6 +125,12 @@ return array(
|
|||
return 'WC-';
|
||||
},
|
||||
'api.bearer' => static function ( ContainerInterface $container ): Bearer {
|
||||
$is_connected = $container->get( 'settings.flag.is-connected' );
|
||||
|
||||
if ( ! $is_connected ) {
|
||||
return new ConnectBearer();
|
||||
}
|
||||
|
||||
return new PayPalBearer(
|
||||
$container->get( 'api.paypal-bearer-cache' ),
|
||||
$container->get( 'api.host' ),
|
||||
|
@ -811,7 +826,7 @@ return array(
|
|||
return new OrderHelper();
|
||||
},
|
||||
'api.helper.order-transient' => static function( ContainerInterface $container ): OrderTransient {
|
||||
$cache = new Cache( 'ppcp-paypal-bearer' );
|
||||
$cache = $container->get( 'api.paypal-bearer-cache' );
|
||||
$purchase_unit_sanitizer = $container->get( 'api.helper.purchase-unit-sanitizer' );
|
||||
return new OrderTransient( $cache, $purchase_unit_sanitizer );
|
||||
},
|
||||
|
@ -927,4 +942,22 @@ return array(
|
|||
$container->get( 'api.endpoint.partner-referrals-sandbox' )
|
||||
);
|
||||
},
|
||||
'api.sandbox-host' => static function ( ContainerInterface $container ): string {
|
||||
$is_connected = $container->get( 'settings.flag.is-connected' );
|
||||
|
||||
if ( $is_connected ) {
|
||||
return PAYPAL_SANDBOX_API_URL;
|
||||
}
|
||||
|
||||
return CONNECT_WOO_SANDBOX_URL;
|
||||
},
|
||||
'api.production-host' => static function ( ContainerInterface $container ): string {
|
||||
$is_connected = $container->get( 'settings.flag.is-connected' );
|
||||
|
||||
if ( $is_connected ) {
|
||||
return PAYPAL_API_URL;
|
||||
}
|
||||
|
||||
return CONNECT_WOO_URL;
|
||||
},
|
||||
);
|
||||
|
|
208
modules/ppcp-api-client/src/Helper/ProductStatus.php
Normal file
208
modules/ppcp-api-client/src/Helper/ProductStatus.php
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
/**
|
||||
* Eligibility status.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Helper
|
||||
*/
|
||||
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Helper;
|
||||
|
||||
use RuntimeException;
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class ProductStatus
|
||||
*
|
||||
* Base class to check the eligibility of a product for the current merchant.
|
||||
*/
|
||||
abstract class ProductStatus {
|
||||
/**
|
||||
* Caches the SellerStatus API response to avoid duplicate API calls
|
||||
* during the same request.
|
||||
*
|
||||
* @var ?SellerStatus
|
||||
*/
|
||||
private static ?SellerStatus $seller_status = null;
|
||||
|
||||
/**
|
||||
* The current status stored in memory.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
private ?bool $is_eligible = null;
|
||||
|
||||
/**
|
||||
* If there was a request failure.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private bool $has_request_failure = false;
|
||||
|
||||
/**
|
||||
* Whether the merchant onboarding process was completed and the
|
||||
* merchant API is available.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private bool $is_connected;
|
||||
|
||||
/**
|
||||
* The partners endpoint.
|
||||
*
|
||||
* @var PartnersEndpoint
|
||||
*/
|
||||
private PartnersEndpoint $partners_endpoint;
|
||||
|
||||
/**
|
||||
* The API failure registry
|
||||
*
|
||||
* @var FailureRegistry
|
||||
*/
|
||||
private FailureRegistry $api_failure_registry;
|
||||
|
||||
/**
|
||||
* AppleProductStatus constructor.
|
||||
*
|
||||
* @param bool $is_connected Whether the merchant is connected.
|
||||
* @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
|
||||
* @param FailureRegistry $api_failure_registry The API failure registry.
|
||||
*/
|
||||
public function __construct(
|
||||
bool $is_connected,
|
||||
PartnersEndpoint $partners_endpoint,
|
||||
FailureRegistry $api_failure_registry
|
||||
) {
|
||||
$this->is_connected = $is_connected;
|
||||
$this->partners_endpoint = $partners_endpoint;
|
||||
$this->api_failure_registry = $api_failure_registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses local data (DB values, hooks) to determine if the feature is eligible.
|
||||
*
|
||||
* Returns true when the feature is available, and false if ineligible.
|
||||
* On failure, an RuntimeException is thrown.
|
||||
*
|
||||
* @return null|bool Boolean to indicate the status; null if the status not locally defined.
|
||||
* @throws RuntimeException When the check failed.
|
||||
* @throws NotFoundException When a relevant service or setting was not found.
|
||||
*/
|
||||
abstract protected function check_local_state() : ?bool;
|
||||
|
||||
/**
|
||||
* Inspects the API response of the SellerStatus to determine feature eligibility.
|
||||
*
|
||||
* Returns true when the feature is available, and false if ineligible.
|
||||
* On failure, an RuntimeException is thrown.
|
||||
*
|
||||
* @param SellerStatus $seller_status The seller status, returned from the API.
|
||||
* @return bool
|
||||
* @throws RuntimeException When the check failed.
|
||||
*/
|
||||
abstract protected function check_active_state( SellerStatus $seller_status ) : bool;
|
||||
|
||||
/**
|
||||
* Clears the eligibility status from the local cache/DB to enforce a new
|
||||
* API call on the next eligibility check.
|
||||
*
|
||||
* @param Settings|null $settings See description in {@see self::clear()}.
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function clear_state( Settings $settings = null ) : void;
|
||||
|
||||
/**
|
||||
* Whether the merchant has access to the feature.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active() : bool {
|
||||
if ( null !== $this->is_eligible ) {
|
||||
return $this->is_eligible;
|
||||
}
|
||||
|
||||
$this->is_eligible = false;
|
||||
$this->has_request_failure = false;
|
||||
|
||||
if ( ! $this->is_onboarded() ) {
|
||||
return $this->is_eligible;
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to use filters and DB values to determine the state.
|
||||
$local_state = $this->check_local_state();
|
||||
if ( null !== $local_state ) {
|
||||
$this->is_eligible = $local_state;
|
||||
|
||||
return $this->is_eligible;
|
||||
}
|
||||
|
||||
// Check using the merchant-API.
|
||||
$seller_status = $this->get_seller_status_object();
|
||||
$this->is_eligible = $this->check_active_state( $seller_status );
|
||||
} catch ( Exception $exception ) {
|
||||
$this->has_request_failure = true;
|
||||
}
|
||||
|
||||
return $this->is_eligible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the seller-status object from the PayPal merchant API.
|
||||
*
|
||||
* @return SellerStatus
|
||||
* @throws RuntimeException When the check failed.
|
||||
*/
|
||||
protected function get_seller_status_object() : SellerStatus {
|
||||
if ( null === self::$seller_status ) {
|
||||
// Check API failure registry to prevent multiple failed API requests.
|
||||
if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, MINUTE_IN_SECONDS ) ) {
|
||||
throw new RuntimeException( 'Timeout for re-check not reached yet' );
|
||||
}
|
||||
|
||||
// Request seller status via PayPal API, might throw an Exception.
|
||||
self::$seller_status = $this->partners_endpoint->seller_status();
|
||||
}
|
||||
|
||||
return self::$seller_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the merchant was fully onboarded, and we have valid API credentials.
|
||||
*
|
||||
* @return bool True, if we can use the merchant API endpoints.
|
||||
*/
|
||||
public function is_onboarded() : bool {
|
||||
return $this->is_connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if there was a request failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_request_failure() : bool {
|
||||
return $this->has_request_failure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the persisted result to force a recheck.
|
||||
*
|
||||
* Accepts a Settings object to don't override other sequential settings that are being updated
|
||||
* elsewhere.
|
||||
*
|
||||
* @param Settings|null $settings The settings object.
|
||||
* @return void
|
||||
*/
|
||||
public function clear( Settings $settings = null ) : void {
|
||||
$this->is_eligible = null;
|
||||
$this->has_request_failure = false;
|
||||
|
||||
$this->clear_state( $settings );
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Applepay;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
|
|
|
@ -19,7 +19,7 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
|||
use WooCommerce\PayPalCommerce\Applepay\Helper\ApmApplies;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Helper\AvailabilityNotice;
|
||||
use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -79,7 +79,7 @@ return array(
|
|||
return new AppleProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'settings.flag.is-connected' ),
|
||||
$container->get( 'api.helper.failure-registry' )
|
||||
);
|
||||
}
|
||||
|
@ -308,5 +308,4 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
|
||||
);
|
||||
|
|
|
@ -17,7 +17,7 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
|||
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Helper\AvailabilityNotice;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
|
||||
|
@ -183,7 +183,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule
|
|||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_rest_common_merchant_data',
|
||||
'woocommerce_paypal_payments_rest_common_merchant_features',
|
||||
function( array $features ) use ( $c ): array {
|
||||
$product_status = $c->get( 'applepay.apple-product-status' );
|
||||
assert( $product_status instanceof AppleProductStatus );
|
||||
|
|
|
@ -5,134 +5,70 @@
|
|||
* @package WooCommerce\PayPalCommerce\Applepay\Assets
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay\Assets;
|
||||
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusCapability;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus;
|
||||
|
||||
/**
|
||||
* Class AppleProductStatus
|
||||
*/
|
||||
class AppleProductStatus {
|
||||
const CAPABILITY_NAME = 'APPLE_PAY';
|
||||
const SETTINGS_KEY = 'products_apple_enabled';
|
||||
class AppleProductStatus extends ProductStatus {
|
||||
public const CAPABILITY_NAME = 'APPLE_PAY';
|
||||
public const SETTINGS_KEY = 'products_apple_enabled';
|
||||
|
||||
const SETTINGS_VALUE_ENABLED = 'yes';
|
||||
const SETTINGS_VALUE_DISABLED = 'no';
|
||||
const SETTINGS_VALUE_UNDEFINED = '';
|
||||
|
||||
/**
|
||||
* The current status stored in memory.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
private $current_status = null;
|
||||
|
||||
/**
|
||||
* If there was a request failure.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $has_request_failure = false;
|
||||
public const SETTINGS_VALUE_ENABLED = 'yes';
|
||||
public const SETTINGS_VALUE_DISABLED = 'no';
|
||||
public const SETTINGS_VALUE_UNDEFINED = '';
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The partners endpoint.
|
||||
*
|
||||
* @var PartnersEndpoint
|
||||
*/
|
||||
private $partners_endpoint;
|
||||
|
||||
/**
|
||||
* The onboarding status
|
||||
*
|
||||
* @var State
|
||||
*/
|
||||
private $onboarding_state;
|
||||
|
||||
/**
|
||||
* The API failure registry
|
||||
*
|
||||
* @var FailureRegistry
|
||||
*/
|
||||
private $api_failure_registry;
|
||||
private Settings $settings;
|
||||
|
||||
/**
|
||||
* AppleProductStatus constructor.
|
||||
*
|
||||
* @param Settings $settings The Settings.
|
||||
* @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
|
||||
* @param State $onboarding_state The onboarding state.
|
||||
* @param bool $is_connected The onboarding state.
|
||||
* @param FailureRegistry $api_failure_registry The API failure registry.
|
||||
*/
|
||||
public function __construct(
|
||||
Settings $settings,
|
||||
PartnersEndpoint $partners_endpoint,
|
||||
State $onboarding_state,
|
||||
bool $is_connected,
|
||||
FailureRegistry $api_failure_registry
|
||||
) {
|
||||
parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry );
|
||||
|
||||
$this->settings = $settings;
|
||||
$this->partners_endpoint = $partners_endpoint;
|
||||
$this->onboarding_state = $onboarding_state;
|
||||
$this->api_failure_registry = $api_failure_registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the active/subscribed products support Applepay.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active() : bool {
|
||||
|
||||
// If not onboarded then makes no sense to check status.
|
||||
if ( ! $this->is_onboarded() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_local_state() : ?bool {
|
||||
$status_override = apply_filters( 'woocommerce_paypal_payments_apple_pay_product_status', null );
|
||||
if ( null !== $status_override ) {
|
||||
return $status_override;
|
||||
}
|
||||
|
||||
// If status was already checked on this request return the same result.
|
||||
if ( null !== $this->current_status ) {
|
||||
return $this->current_status;
|
||||
}
|
||||
|
||||
// Check if status was checked on previous requests.
|
||||
if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) {
|
||||
$this->current_status = wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) );
|
||||
return $this->current_status;
|
||||
return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) );
|
||||
}
|
||||
|
||||
// Check API failure registry to prevent multiple failed API requests.
|
||||
if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, HOUR_IN_SECONDS ) ) {
|
||||
$this->has_request_failure = true;
|
||||
$this->current_status = false;
|
||||
return $this->current_status;
|
||||
}
|
||||
|
||||
// Request seller status via PayPal API.
|
||||
try {
|
||||
$seller_status = $this->partners_endpoint->seller_status();
|
||||
} catch ( Throwable $error ) {
|
||||
$this->has_request_failure = true;
|
||||
$this->current_status = false;
|
||||
return $this->current_status;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_active_state( SellerStatus $seller_status ) : bool {
|
||||
// Check the seller status for the intended capability.
|
||||
$has_capability = false;
|
||||
foreach ( $seller_status->products() as $product ) {
|
||||
|
@ -145,65 +81,33 @@ class AppleProductStatus {
|
|||
}
|
||||
}
|
||||
|
||||
if ( ! $has_capability ) {
|
||||
foreach ( $seller_status->capabilities() as $capability ) {
|
||||
if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) {
|
||||
$has_capability = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_capability ) {
|
||||
// Capability found, persist status and return true.
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED );
|
||||
$this->settings->persist();
|
||||
|
||||
$this->current_status = true;
|
||||
return $this->current_status;
|
||||
}
|
||||
|
||||
// Capability not found, persist status and return false.
|
||||
} else {
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED );
|
||||
}
|
||||
$this->settings->persist();
|
||||
|
||||
$this->current_status = false;
|
||||
return $this->current_status;
|
||||
return $has_capability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the seller is onboarded.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_onboarded(): bool {
|
||||
return $this->onboarding_state->current_state() >= State::STATE_ONBOARDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if there was a request failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_request_failure(): bool {
|
||||
return $this->has_request_failure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the persisted result to force a recheck.
|
||||
*
|
||||
* @param Settings|null $settings The settings object.
|
||||
* We accept a Settings object to don't override other sequential settings that are being updated elsewhere.
|
||||
* @return void
|
||||
*/
|
||||
public function clear( Settings $settings = null ): void {
|
||||
/** {@inheritDoc} */
|
||||
protected function clear_state( Settings $settings = null ) : void {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->settings;
|
||||
}
|
||||
|
||||
$this->current_status = null;
|
||||
|
||||
if ( $settings->has( self::SETTINGS_KEY ) ) {
|
||||
$settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED );
|
||||
$settings->persist();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use WC_Payment_Gateway;
|
|||
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
|
||||
use WooCommerce\PayPalCommerce\Axo\FrontendLoggerEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCGatewayConfiguration;
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace WooCommerce\PayPalCommerce\Axo\Assets;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\CurrencyGetter;
|
||||
use WooCommerce\PayPalCommerce\Axo\FrontendLoggerEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
|
|
@ -19,7 +19,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\GatewaySettingsRendererTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
|
@ -175,12 +175,13 @@ class AxoGateway extends WC_Payment_Gateway {
|
|||
$this->method_title = __( 'Fastlane Debit & Credit Cards', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'Fastlane accelerates the checkout experience for guest shoppers and autofills their details so they can pay in seconds. When enabled, Fastlane is presented as the default payment method for guests.', 'woocommerce-paypal-payments' );
|
||||
|
||||
if ( apply_filters( 'woocommerce_paypal_payments_axo_gateway_should_update_enabled', true ) ) {
|
||||
$is_axo_enabled = $this->dcc_configuration->use_fastlane();
|
||||
$this->update_option( 'enabled', $is_axo_enabled ? 'yes' : 'no' );
|
||||
}
|
||||
|
||||
$this->title = $this->dcc_configuration->gateway_title( $this->get_option( 'title', $this->method_title ) );
|
||||
|
||||
$this->description = __( 'Enter your email address above to continue.', 'woocommerce-paypal-payments' );
|
||||
$this->title = apply_filters( 'woocommerce_paypal_payments_axo_gateway_title', $this->dcc_configuration->gateway_title( $this->get_option( 'title', $this->method_title ) ), $this );
|
||||
$this->description = apply_filters( 'woocommerce_paypal_payments_axo_gateway_description', __( 'Enter your email address above to continue.', 'woocommerce-paypal-payments' ), $this );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
|
|
@ -35,7 +35,7 @@ use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCGatewayConfiguration;
|
||||
|
|
|
@ -36,7 +36,7 @@ use WooCommerce\PayPalCommerce\Button\Endpoint\ValidateCheckoutEndpoint;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\DisabledFundingSources;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\PayLaterBlock\PayLaterBlockModule;
|
||||
use WooCommerce\PayPalCommerce\PayLaterWCBlocks\PayLaterWCBlocksModule;
|
||||
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
|
||||
|
|
|
@ -128,13 +128,6 @@ return array(
|
|||
}
|
||||
|
||||
return array(
|
||||
new SettingsMap(
|
||||
$container->get( 'settings.data.general' ),
|
||||
array(
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
)
|
||||
),
|
||||
new SettingsMap(
|
||||
$container->get( 'settings.data.general' ),
|
||||
/**
|
||||
|
@ -145,7 +138,10 @@ return array(
|
|||
* the credentials are used for.
|
||||
*/
|
||||
array(
|
||||
'is_sandbox' => 'sandbox_merchant',
|
||||
'merchant_id' => 'merchant_id',
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'sandbox_on' => 'sandbox_merchant',
|
||||
'live_client_id' => 'client_id',
|
||||
'live_client_secret' => 'client_secret',
|
||||
'live_merchant_id' => 'merchant_id',
|
||||
|
|
|
@ -18,7 +18,7 @@ use WooCommerce\PayPalCommerce\Googlepay\Endpoint\UpdatePaymentDataEndpoint;
|
|||
use WooCommerce\PayPalCommerce\Googlepay\Helper\ApmApplies;
|
||||
use WooCommerce\PayPalCommerce\Googlepay\Helper\ApmProductStatus;
|
||||
use WooCommerce\PayPalCommerce\Googlepay\Helper\AvailabilityNotice;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -75,7 +75,7 @@ return array(
|
|||
return new ApmProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'settings.flag.is-connected' ),
|
||||
$container->get( 'api.helper.failure-registry' )
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\Googlepay\Endpoint\UpdatePaymentDataEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
|
|
|
@ -233,7 +233,7 @@ class GooglepayModule implements ServiceModule, ExtendingModule, ExecutableModul
|
|||
);
|
||||
|
||||
add_filter(
|
||||
'woocommerce_paypal_payments_rest_common_merchant_data',
|
||||
'woocommerce_paypal_payments_rest_common_merchant_features',
|
||||
function ( array $features ) use ( $c ): array {
|
||||
$product_status = $c->get( 'googlepay.helpers.apm-product-status' );
|
||||
assert( $product_status instanceof ApmProductStatus );
|
||||
|
|
|
@ -9,130 +9,66 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Googlepay\Helper;
|
||||
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusCapability;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus;
|
||||
|
||||
/**
|
||||
* Class ApmProductStatus
|
||||
*/
|
||||
class ApmProductStatus {
|
||||
const CAPABILITY_NAME = 'GOOGLE_PAY';
|
||||
const SETTINGS_KEY = 'products_googlepay_enabled';
|
||||
class ApmProductStatus extends ProductStatus {
|
||||
public const CAPABILITY_NAME = 'GOOGLE_PAY';
|
||||
public const SETTINGS_KEY = 'products_googlepay_enabled';
|
||||
|
||||
const SETTINGS_VALUE_ENABLED = 'yes';
|
||||
const SETTINGS_VALUE_DISABLED = 'no';
|
||||
const SETTINGS_VALUE_UNDEFINED = '';
|
||||
|
||||
/**
|
||||
* The current status stored in memory.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
private $current_status = null;
|
||||
|
||||
/**
|
||||
* If there was a request failure.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $has_request_failure = false;
|
||||
public const SETTINGS_VALUE_ENABLED = 'yes';
|
||||
public const SETTINGS_VALUE_DISABLED = 'no';
|
||||
public const SETTINGS_VALUE_UNDEFINED = '';
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The partners endpoint.
|
||||
*
|
||||
* @var PartnersEndpoint
|
||||
*/
|
||||
private $partners_endpoint;
|
||||
|
||||
/**
|
||||
* The onboarding status
|
||||
*
|
||||
* @var State
|
||||
*/
|
||||
private $onboarding_state;
|
||||
|
||||
/**
|
||||
* The API failure registry
|
||||
*
|
||||
* @var FailureRegistry
|
||||
*/
|
||||
private $api_failure_registry;
|
||||
private Settings $settings;
|
||||
|
||||
/**
|
||||
* ApmProductStatus constructor.
|
||||
*
|
||||
* @param Settings $settings The Settings.
|
||||
* @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
|
||||
* @param State $onboarding_state The onboarding state.
|
||||
* @param bool $is_connected The onboarding state.
|
||||
* @param FailureRegistry $api_failure_registry The API failure registry.
|
||||
*/
|
||||
public function __construct(
|
||||
Settings $settings,
|
||||
PartnersEndpoint $partners_endpoint,
|
||||
State $onboarding_state,
|
||||
bool $is_connected,
|
||||
FailureRegistry $api_failure_registry
|
||||
) {
|
||||
parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry );
|
||||
|
||||
$this->settings = $settings;
|
||||
$this->partners_endpoint = $partners_endpoint;
|
||||
$this->onboarding_state = $onboarding_state;
|
||||
$this->api_failure_registry = $api_failure_registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the active/subscribed products support Googlepay.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_active() : bool {
|
||||
|
||||
// If not onboarded then makes no sense to check status.
|
||||
if ( ! $this->is_onboarded() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_local_state() : ?bool {
|
||||
$status_override = apply_filters( 'woocommerce_paypal_payments_google_pay_product_status', null );
|
||||
if ( null !== $status_override ) {
|
||||
return $status_override;
|
||||
}
|
||||
|
||||
// If status was already checked on this request return the same result.
|
||||
if ( null !== $this->current_status ) {
|
||||
return $this->current_status;
|
||||
}
|
||||
|
||||
// Check if status was checked on previous requests.
|
||||
if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) {
|
||||
$this->current_status = wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) );
|
||||
return $this->current_status;
|
||||
return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) );
|
||||
}
|
||||
|
||||
// Check API failure registry to prevent multiple failed API requests.
|
||||
if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, HOUR_IN_SECONDS ) ) {
|
||||
$this->has_request_failure = true;
|
||||
$this->current_status = false;
|
||||
return $this->current_status;
|
||||
}
|
||||
|
||||
// Request seller status via PayPal API.
|
||||
try {
|
||||
$seller_status = $this->partners_endpoint->seller_status();
|
||||
} catch ( Throwable $error ) {
|
||||
$this->has_request_failure = true;
|
||||
$this->current_status = false;
|
||||
return $this->current_status;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_active_state( SellerStatus $seller_status ) : bool {
|
||||
// Check the seller status for the intended capability.
|
||||
$has_capability = false;
|
||||
foreach ( $seller_status->products() as $product ) {
|
||||
|
@ -145,65 +81,33 @@ class ApmProductStatus {
|
|||
}
|
||||
}
|
||||
|
||||
if ( ! $has_capability ) {
|
||||
foreach ( $seller_status->capabilities() as $capability ) {
|
||||
if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) {
|
||||
$has_capability = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_capability ) {
|
||||
// Capability found, persist status and return true.
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED );
|
||||
$this->settings->persist();
|
||||
|
||||
$this->current_status = true;
|
||||
return $this->current_status;
|
||||
}
|
||||
|
||||
// Capability not found, persist status and return false.
|
||||
} else {
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED );
|
||||
}
|
||||
$this->settings->persist();
|
||||
|
||||
$this->current_status = false;
|
||||
return $this->current_status;
|
||||
return $has_capability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the seller is onboarded.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_onboarded(): bool {
|
||||
return $this->onboarding_state->current_state() >= State::STATE_ONBOARDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if there was a request failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_request_failure(): bool {
|
||||
return $this->has_request_failure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the persisted result to force a recheck.
|
||||
*
|
||||
* @param Settings|null $settings The settings object.
|
||||
* We accept a Settings object to don't override other sequential settings that are being updated elsewhere.
|
||||
* @return void
|
||||
*/
|
||||
public function clear( Settings $settings = null ): void {
|
||||
/** {@inheritDoc} */
|
||||
protected function clear_state( Settings $settings = null ) : void {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->settings;
|
||||
}
|
||||
|
||||
$this->current_status = null;
|
||||
|
||||
if ( $settings->has( self::SETTINGS_KEY ) ) {
|
||||
$settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED );
|
||||
$settings->persist();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\LocalApmProductStatus;
|
||||
|
||||
return array(
|
||||
'ppcp-local-apms.url' => static function ( ContainerInterface $container ): string {
|
||||
|
@ -67,6 +68,14 @@ return array(
|
|||
),
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.product-status' => static function ( ContainerInterface $container ): LocalApmProductStatus {
|
||||
return new LocalApmProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
$container->get( 'settings.flag.is-connected' ),
|
||||
$container->get( 'api.helper.failure-registry' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.bancontact.wc-gateway' => static function ( ContainerInterface $container ): BancontactGateway {
|
||||
return new BancontactGateway(
|
||||
$container->get( 'api.endpoint.orders' ),
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
/**
|
||||
* Status of local alternative payment methods.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods
|
||||
*/
|
||||
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus;
|
||||
|
||||
/**
|
||||
* Class LocalApmProductStatus
|
||||
*/
|
||||
class LocalApmProductStatus extends ProductStatus {
|
||||
public const SETTINGS_KEY = 'products_local_apms_enabled';
|
||||
|
||||
public const SETTINGS_VALUE_ENABLED = 'yes';
|
||||
public const SETTINGS_VALUE_DISABLED = 'no';
|
||||
public const SETTINGS_VALUE_UNDEFINED = '';
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private Settings $settings;
|
||||
|
||||
/**
|
||||
* ApmProductStatus constructor.
|
||||
*
|
||||
* @param Settings $settings The Settings.
|
||||
* @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
|
||||
* @param bool $is_connected The onboarding state.
|
||||
* @param FailureRegistry $api_failure_registry The API failure registry.
|
||||
*/
|
||||
public function __construct(
|
||||
Settings $settings,
|
||||
PartnersEndpoint $partners_endpoint,
|
||||
bool $is_connected,
|
||||
FailureRegistry $api_failure_registry
|
||||
) {
|
||||
parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry );
|
||||
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_local_state() : ?bool {
|
||||
if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) {
|
||||
return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function check_active_state( SellerStatus $seller_status ) : bool {
|
||||
$has_capability = false;
|
||||
|
||||
foreach ( $seller_status->products() as $product ) {
|
||||
if ( $product->name() === 'PAYMENT_METHODS' ) {
|
||||
$has_capability = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $has_capability ) {
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED );
|
||||
} else {
|
||||
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED );
|
||||
}
|
||||
$this->settings->persist();
|
||||
|
||||
return $has_capability;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected function clear_state( Settings $settings = null ) : void {
|
||||
if ( null === $settings ) {
|
||||
$settings = $this->settings;
|
||||
}
|
||||
|
||||
if ( $settings->has( self::SETTINGS_KEY ) ) {
|
||||
$settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED );
|
||||
$settings->persist();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -141,6 +141,7 @@ class TrustlyGateway extends WC_Payment_Gateway {
|
|||
'trustly' => array(
|
||||
'country_code' => $wc_order->get_billing_country(),
|
||||
'name' => $wc_order->get_billing_first_name() . ' ' . $wc_order->get_billing_last_name(),
|
||||
'email' => $wc_order->get_billing_email(),
|
||||
),
|
||||
),
|
||||
'processing_instruction' => 'ORDER_COMPLETE_ON_PAYMENT_APPROVAL',
|
||||
|
|
|
@ -11,58 +11,15 @@ namespace WooCommerce\PayPalCommerce\Onboarding;
|
|||
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\ConnectBearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Assets\OnboardingAssets;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Endpoint\UpdateSignupLinksEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingSendOnlyNoticeRenderer;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
|
||||
return array(
|
||||
'api.sandbox-host' => static function ( ContainerInterface $container ): string {
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
|
||||
/**
|
||||
* The State object.
|
||||
*
|
||||
* @var State $state
|
||||
*/
|
||||
if ( $state->current_state() >= State::STATE_ONBOARDED ) {
|
||||
return PAYPAL_SANDBOX_API_URL;
|
||||
}
|
||||
return CONNECT_WOO_SANDBOX_URL;
|
||||
},
|
||||
'api.production-host' => static function ( ContainerInterface $container ): string {
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
|
||||
/**
|
||||
* The Environment and State variables.
|
||||
*
|
||||
* @var Environment $environment
|
||||
* @var State $state
|
||||
*/
|
||||
if ( $state->current_state() >= State::STATE_ONBOARDED ) {
|
||||
return PAYPAL_API_URL;
|
||||
}
|
||||
return CONNECT_WOO_URL;
|
||||
},
|
||||
'api.host' => static function ( ContainerInterface $container ): string {
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
|
||||
/**
|
||||
* The Environment and State variables.
|
||||
*
|
||||
* @var Environment $environment
|
||||
*/
|
||||
return $environment->current_environment_is( Environment::SANDBOX )
|
||||
? (string) $container->get( 'api.sandbox-host' ) : (string) $container->get( 'api.production-host' );
|
||||
|
||||
},
|
||||
'api.paypal-host' => function( ContainerInterface $container ) : string {
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
/**
|
||||
|
@ -85,38 +42,20 @@ return array(
|
|||
return $container->get( 'api.paypal-website-url-production' );
|
||||
|
||||
},
|
||||
|
||||
'api.bearer' => static function ( ContainerInterface $container ): Bearer {
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
|
||||
/**
|
||||
* The State.
|
||||
*
|
||||
* @var State $state
|
||||
*/
|
||||
if ( $state->current_state() < State::STATE_ONBOARDED ) {
|
||||
return new ConnectBearer();
|
||||
}
|
||||
$cache = new Cache( 'ppcp-paypal-bearer' );
|
||||
$key = $container->get( 'api.key' );
|
||||
$secret = $container->get( 'api.secret' );
|
||||
$host = $container->get( 'api.host' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new PayPalBearer(
|
||||
$cache,
|
||||
$host,
|
||||
$key,
|
||||
$secret,
|
||||
$logger,
|
||||
$settings
|
||||
);
|
||||
},
|
||||
'onboarding.state' => function( ContainerInterface $container ) : State {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new State( $settings );
|
||||
},
|
||||
/**
|
||||
* Checks if the onboarding process is completed and the merchant API can be used.
|
||||
* This service is overwritten by the ppcp-settings module, when it's active.
|
||||
*/
|
||||
'settings.flag.is-connected' => static function ( ContainerInterface $container ) : bool {
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
assert( $state instanceof State );
|
||||
|
||||
return $state->current_state() >= State::STATE_ONBOARDED;
|
||||
},
|
||||
'onboarding.environment' => function( ContainerInterface $container ) : Environment {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new Environment( $settings );
|
||||
|
@ -149,7 +88,7 @@ return array(
|
|||
$login_seller_sandbox = $container->get( 'api.endpoint.login-seller-sandbox' );
|
||||
$partner_referrals_data = $container->get( 'api.repository.partner-referrals-data' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$cache = new Cache( 'ppcp-paypal-bearer' );
|
||||
$cache = $container->get( 'api.paypal-bearer-cache' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new LoginSellerEndpoint(
|
||||
$request_data,
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace WooCommerce\PayPalCommerce\Onboarding\Assets;
|
|||
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Endpoint\UpdateSignupLinksEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Used to detect the current environment.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Onboarding
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Onboarding;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Class Environment
|
||||
*/
|
||||
class Environment {
|
||||
|
||||
|
||||
const PRODUCTION = 'production';
|
||||
const SANDBOX = 'sandbox';
|
||||
|
||||
/**
|
||||
* The Settings.
|
||||
*
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Environment constructor.
|
||||
*
|
||||
* @param ContainerInterface $settings The Settings.
|
||||
*/
|
||||
public function __construct( ContainerInterface $settings ) {
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current environment.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function current_environment(): string {
|
||||
return (
|
||||
$this->settings->has( 'sandbox_on' ) && $this->settings->get( 'sandbox_on' )
|
||||
) ? self::SANDBOX : self::PRODUCTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect whether the current environment equals $environment
|
||||
*
|
||||
* @param string $environment The value to check against.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function current_environment_is( string $environment ): bool {
|
||||
return $this->current_environment() === $environment;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Onboarding;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
|
||||
/**
|
||||
* Class State
|
||||
|
|
|
@ -94,7 +94,7 @@ class SaveConfig {
|
|||
*
|
||||
* @param array $config The configurator config.
|
||||
*/
|
||||
private function save_config( array $config ): void {
|
||||
public function save_config( array $config ): void {
|
||||
$this->settings->set( 'pay_later_enable_styling_per_messaging_location', true );
|
||||
$this->settings->set( 'pay_later_messaging_enabled', true );
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use WC_Subscriptions_Product;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
}
|
||||
|
||||
@mixin hide-input-field() {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
|
|
@ -19,7 +19,6 @@ $color-divider: #F0F0F0;
|
|||
$color-error-red: #cc1818;
|
||||
|
||||
$shadow-card: 0 3px 6px 0 rgba(0, 0, 0, 0.15);
|
||||
$shadow-selection-box: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
|
||||
$color-gradient-dark: #001435;
|
||||
$gradient-header: linear-gradient(87.03deg, #003087 -0.49%, #001E51 29.22%, $color-gradient-dark 100%);
|
||||
|
||||
|
@ -71,4 +70,15 @@ $card-vertical-gap: 48px;
|
|||
--block-separator-size: 1px;
|
||||
--block-separator-color: var(--color-gray-200);
|
||||
--block-action-gap: 16px; // Space between two consecutive action blocks.
|
||||
|
||||
// Default visual effects.
|
||||
--box-shadow-active-item: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
|
||||
--container-border-radius: 8px;
|
||||
|
||||
// Spinner/loader.
|
||||
--spinner-size: 20px;
|
||||
--spinner-overlay-width: 320px;
|
||||
--spinner-overlay-height: 320px;
|
||||
--spinner-overlay-color: #fafafa;
|
||||
--spinner-overlay-box-shadow: var(--box-shadow-active-item);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
@import './reusable-components/button';
|
||||
@import './reusable-components/elements';
|
||||
@import './reusable-components/fields';
|
||||
@import './reusable-components/hstack';
|
||||
@import './reusable-components/navigation';
|
||||
@import './reusable-components/onboarding-header';
|
||||
@import './reusable-components/payment-method-icons';
|
||||
|
@ -16,6 +15,7 @@
|
|||
@import './reusable-components/settings-toggle-block';
|
||||
@import './reusable-components/settings-wrapper';
|
||||
@import './reusable-components/spinner-overlay';
|
||||
@import './reusable-components/stack';
|
||||
@import './reusable-components/tab-navigation';
|
||||
@import './reusable-components/title-badge';
|
||||
@import './reusable-components/welcome-docs';
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
.ppcp-r-badge-box {
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
&__title {
|
||||
.ppcp-r-badge-box__title {
|
||||
@include font(14, 20, 700);
|
||||
display: block;
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
.ppcp-r-badge-box__title-text {
|
||||
color: #000;
|
||||
|
||||
&--big {
|
||||
@include font(16, 28, 700);
|
||||
}
|
||||
|
||||
&--small {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.ppcp-r-badge-box__title-text:not(:empty) + .ppcp-r-badge-box__title-image-badge {
|
||||
|
@ -27,13 +20,20 @@
|
|||
height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--has-image-badge .ppcp-r-title-badge--info {
|
||||
.ppcp-r-badge-box__title--has-image-badge .ppcp-r-title-badge--info {
|
||||
display: block;
|
||||
margin: 6px 0px 0px 0px;
|
||||
margin: 6px 0 0 0;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.components-button.is-tertiary {
|
||||
padding: 0;
|
||||
margin: 0 0 0 4px;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
@ -42,10 +42,10 @@
|
|||
flex-direction: column;
|
||||
|
||||
.ppcp-r-badge-box__title-text:not(:empty) + .ppcp-r-badge-box__title-image-badge {
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
|
||||
img:first-of-type {
|
||||
margin: 0px;
|
||||
}
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ button.components-button, a.components-button {
|
|||
|
||||
/* style the button template */
|
||||
|
||||
text-align: center;
|
||||
|
||||
&:not(:disabled) {
|
||||
@extend %button-style-default;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
.ppcp-r-title-badge {
|
||||
text-transform: none;
|
||||
margin-left: 6px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
.ppcp-r-app {
|
||||
.components-flex {
|
||||
display: flex;
|
||||
-webkit-box-align: stretch;
|
||||
align-items: stretch;
|
||||
-webkit-box-pack: center;
|
||||
|
||||
.components-h-stack {
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.components-v-stack {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// Fix layout for checkboxes inside a flex-stack.
|
||||
.components-checkbox-control > .components-base-control__field > .components-flex {
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp--horizontal {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
|
@ -1,24 +1,33 @@
|
|||
$margin_bottom: 48px;
|
||||
|
||||
.ppcp-r-navigation-container {
|
||||
// Theming.
|
||||
--wp-components-color-accent: #{$color-blueberry};
|
||||
--color-text: #{$color-gray-900};
|
||||
--color-disabled: #CCC;
|
||||
--navbar-height: 40px;
|
||||
--navbar-vertical-padding: 10px;
|
||||
--subnavigation-height: 40px;
|
||||
|
||||
// Styling.
|
||||
position: sticky;
|
||||
top: var(--wp-admin--admin-bar--height);
|
||||
z-index: 10;
|
||||
|
||||
padding: 10px 48px;
|
||||
margin: 0 -20px 48px -20px;
|
||||
padding: 0 48px;
|
||||
margin: 0 -20px #{$margin_bottom} -20px;
|
||||
|
||||
box-shadow: 0 -1px 0 0 $color-gray-300 inset;
|
||||
background: var(--ppcp-color-app-bg);
|
||||
transition: box-shadow 0.3s;
|
||||
|
||||
--wp-components-color-accent: #{$color-blueberry};
|
||||
--color-text: #{$color-gray-900};
|
||||
--color-disabled: #CCC;
|
||||
|
||||
.ppcp-r-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
flex-direction: row;
|
||||
height: calc(var(--navbar-height) + (2 * var(--navbar-vertical-padding)));
|
||||
padding: var(--navbar-vertical-padding) 0;
|
||||
|
||||
.components-button {
|
||||
@include font(13, 20, 400);
|
||||
|
@ -57,19 +66,20 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--left {
|
||||
.ppcp-r-navigation--left {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
&--right {
|
||||
.ppcp-r-navigation--right {
|
||||
.is-link {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&--progress-bar {
|
||||
.ppcp-r-navigation--progress-bar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
@ -77,12 +87,25 @@
|
|||
height: 4px;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
&.ppcp--is-scrolled {
|
||||
box-shadow: 0 -1px 0 0 $color-gray-300 inset, 0 8px 8px 0 rgba(85, 93, 102, .3);
|
||||
}
|
||||
|
||||
.ppcp--top-sub-navigation {
|
||||
height: var(--subnavigation-height);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.ppcp-r-tabs {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.components-tab-panel__tabs-item {
|
||||
height: var(--subnavigation-height);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 782px) {
|
||||
padding: 10px 12px;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
gap: 8px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
> img{
|
||||
width: 38px;
|
||||
height: 24px;
|
||||
|
|
|
@ -1,74 +1,80 @@
|
|||
.ppcp-r-settings-block__payment-methods {
|
||||
&.ppcp-r-settings-block {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
}
|
||||
// Grid layout.
|
||||
.ppcp-r-settings-block.ppcp--grid > .ppcp--content {
|
||||
--block-separator-gap: 0;
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
width: calc(100% / 3 - 32px / 3);
|
||||
border: 1px solid $color-gray-300;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
min-height: 200px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
width: calc(50% - 8px);
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
width: 100%;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
&__inner {
|
||||
// Theming & visual styles.
|
||||
.ppcp-r-settings-block__payment-methods {
|
||||
.ppcp-r-settings-block {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
border: 1px solid $color-gray-300;
|
||||
border-radius: var(--container-border-radius);
|
||||
padding: 16px;
|
||||
min-height: 200px;
|
||||
|
||||
.ppcp--method-inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__title-wrapper {
|
||||
.ppcp--method-title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 0 8px 0;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
.ppcp--method-description {
|
||||
p {
|
||||
@include font(13, 20, 400);
|
||||
margin: 0;
|
||||
color: $color-text-tertiary;
|
||||
@include font(13, 20, 400);
|
||||
}
|
||||
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
.ppcp--method-title {
|
||||
@include font(13, 20, 500);
|
||||
color: $color-black;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__settings {
|
||||
line-height: 0;
|
||||
.ppcp--method-settings {
|
||||
padding: 0;
|
||||
transition: 0.2s ease-out transform;
|
||||
transform: rotate(0deg);
|
||||
zoom: 1.005;
|
||||
|
||||
&:hover {
|
||||
transform: rotate(45deg);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp--method-icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
button.is-secondary {
|
||||
@include small-button;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
.ppcp--method-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
.ppcp-r-select-box-wrapper {
|
||||
--box-border-color: var(--color-gray-200);
|
||||
--box-outline-color: transparent;
|
||||
--box-shadow: 0;
|
||||
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
|
@ -6,92 +10,62 @@
|
|||
}
|
||||
|
||||
.ppcp-r-select-box {
|
||||
border: 1px solid var(--box-border-color);
|
||||
outline: 1px solid var(--box-outline-color);
|
||||
box-shadow: var(--box-shadow);
|
||||
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border: 1px solid $color-gray-200;
|
||||
outline: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 24px 16px 24px 16px;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
--box-border-color: var(--color-gray-500);
|
||||
--box-shadow: var(--box-shadow-active-item);
|
||||
}
|
||||
|
||||
&.ppcp--selected {
|
||||
border-color: $color-blueberry;
|
||||
outline-color: $color-blueberry;
|
||||
box-shadow: $shadow-selection-box;
|
||||
--box-border-color: var(--color-blueberry);
|
||||
--box-outline-color: var(--color-blueberry);
|
||||
--box-shadow: var(--box-shadow-active-item);
|
||||
}
|
||||
|
||||
&__radio-value {
|
||||
@include hide-input-field;
|
||||
|
||||
&:checked {
|
||||
+ .ppcp-r-select-box__radio-presentation {
|
||||
background: $color-white;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 6px solid $color-blueberry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__checkbox-value {
|
||||
@include hide-input-field;
|
||||
|
||||
&:not(:checked) + .ppcp-r-select-box__checkbox-presentation img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:checked {
|
||||
+ .ppcp-r-select-box__checkbox-presentation {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: none;
|
||||
|
||||
img {
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
.ppcp--box-content {
|
||||
display: flex;
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
*:not(a){
|
||||
|
||||
*:not(a) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
a {
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
.ppcp--box-title {
|
||||
@include font(14, 20, 700);
|
||||
color: $color-black;
|
||||
margin: 0 0 4px 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__description {
|
||||
.ppcp--box-description {
|
||||
@include font(13, 20, 400);
|
||||
color: $color-gray-700;
|
||||
margin:0;
|
||||
margin: 0;
|
||||
|
||||
&:not(:last-child){
|
||||
margin-block-end:18px;
|
||||
&:not(:last-child) {
|
||||
margin-block-end: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&__radio-presentation {
|
||||
@include fake-input-field(20px);
|
||||
}
|
||||
|
||||
&__checkbox-presentation {
|
||||
@include fake-input-field(2px);
|
||||
}
|
||||
&__additional-content{
|
||||
.ppcp--box-details {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
@ -99,15 +73,18 @@
|
|||
@media screen and (max-width: 480px) {
|
||||
gap: 16px;
|
||||
padding: 18px 16px;
|
||||
&__description {
|
||||
|
||||
.ppcp--box-description {
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
&__content {
|
||||
|
||||
.ppcp--box-content {
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 380px) {
|
||||
&__content > img {
|
||||
.ppcp--box-content > img {
|
||||
max-width: 32px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
// Configuration for this module.
|
||||
$width_container: 938px;
|
||||
$width_header: 280px;
|
||||
$width_gap: 24px;
|
||||
|
||||
/*
|
||||
Styles the `SettingsCard` layout component.
|
||||
|
||||
|
@ -14,9 +19,9 @@
|
|||
--card-layout: block;
|
||||
|
||||
@media screen and (min-width: 960px) {
|
||||
--card-width-header: 280px;
|
||||
--card-width-content: 610px;
|
||||
--card-gap: 48px;
|
||||
--card-width-header: #{$width_header};
|
||||
--card-width-content: #{$width_container - $width_header - $width_gap};
|
||||
--card-gap: #{$width_gap};
|
||||
--card-layout: flex;
|
||||
}
|
||||
|
||||
|
@ -46,6 +51,7 @@
|
|||
&.ppcp--is-card {
|
||||
max-width: var(--card-width-content);
|
||||
border: 1px solid var(--color-gray-200);
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
.ppcp-r {
|
||||
&-container {
|
||||
.ppcp-r-container {
|
||||
max-width: var(--max-container-width, none);
|
||||
margin-right: auto;
|
||||
}
|
||||
margin: 0 auto 0 35px;
|
||||
}
|
||||
|
||||
&-inner-container {
|
||||
.ppcp-r-inner-container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 0 16px 48px;
|
||||
|
@ -13,9 +12,9 @@
|
|||
@media screen and (max-width: 480px) {
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-settings {
|
||||
.ppcp-r-settings {
|
||||
> * {
|
||||
margin-bottom: $card-vertical-gap;
|
||||
}
|
||||
|
@ -24,5 +23,4 @@
|
|||
padding-bottom: $card-vertical-gap;
|
||||
border-bottom: 1px solid $color-gray-200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
.ppcp-r-spinner-overlay {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
width: var(--spinner-overlay-width);
|
||||
height: var(--spinner-overlay-height);
|
||||
box-shadow: var(--spinner-overlay-box-shadow);
|
||||
background: var(--spinner-overlay-color);
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
|
||||
.components-spinner {
|
||||
position: absolute;
|
||||
|
@ -13,5 +15,15 @@
|
|||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
margin: 0;
|
||||
width: var(--spinner-size);
|
||||
height: var(--spinner-size);
|
||||
}
|
||||
|
||||
.ppcp--spinner-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
top: calc(50% + 20px + var(--spinner-size));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
.ppcp-r-app {
|
||||
.components-flex {
|
||||
display: flex;
|
||||
-webkit-box-align: stretch;
|
||||
align-items: stretch;
|
||||
-webkit-box-pack: center;
|
||||
}
|
||||
|
||||
.components-flex.components-h-stack,
|
||||
.ppcp--horizontal {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ppcp--horizontal {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.components-flex.components-v-stack {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
|
@ -1,22 +1,17 @@
|
|||
.ppcp-r-tabs {
|
||||
--wp-components-color-accent: #{$color-blueberry};
|
||||
--wp-admin-border-width-focus: 3px;
|
||||
--wp-admin-border-width-focus: 2px;
|
||||
|
||||
max-width: var(--max-container-width);
|
||||
transition: max-width 0.2s;
|
||||
padding:0 35px;
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
|
||||
.components-tab-panel__tabs {
|
||||
box-shadow: 0 -1px 0 0 $color-gray-400 inset;
|
||||
margin-bottom: 48px;
|
||||
gap: 12px;
|
||||
gap: 0;
|
||||
overflow: auto;
|
||||
|
||||
.components-button {
|
||||
padding: 16px 20px;
|
||||
|
||||
&.is-active {
|
||||
background-color: #fff4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
.ppcp-r-title-badge{
|
||||
.ppcp-r-title-badge {
|
||||
--badge-bg-color: #F5F5F5;
|
||||
--badge-text-color: #2F2F2F;
|
||||
|
||||
color: var(--badge-text-color);
|
||||
background-color: var(--badge-bg-color);
|
||||
|
||||
@include font(12, 16, 400);
|
||||
padding: 4px 8px;
|
||||
border-radius: 2px;
|
||||
white-space: nowrap;
|
||||
&--positive{
|
||||
color: #144722;
|
||||
background-color: #DAFFE0;
|
||||
|
||||
&.ppcp-r-title-badge--positive {
|
||||
--badge-bg-color: #DAFFE0;
|
||||
--badge-text-color: #144722;
|
||||
}
|
||||
&--negative{
|
||||
color:#5c0000;
|
||||
background-color: #faeded;
|
||||
}
|
||||
&--info{
|
||||
color: #2F2F2F;
|
||||
background-color: #F5F5F5;
|
||||
|
||||
&.ppcp-r-title-badge--negative {
|
||||
--badge-bg-color: #faeded;
|
||||
--badge-text-color: #5c0000;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,8 +54,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp-r-page-welcome-mode-separator {
|
||||
margin: 8px 0 24px 0 !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ body:has(.ppcp-r-container--onboarding) {
|
|||
.nav-tab-wrapper.woo-nav-tab-wrapper,
|
||||
.woocommerce-layout__header,
|
||||
.wrap.woocommerce form > h2,
|
||||
#mainform .subsubsub,
|
||||
#mainform .subsubsub + br.clear,
|
||||
#screen-meta-links {
|
||||
display: none !important;
|
||||
visibility: hidden;
|
||||
|
|
|
@ -7,7 +7,14 @@
|
|||
.ppcp-r-container--onboarding {
|
||||
--max-container-width: var(--max-width-onboarding);
|
||||
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
.ppcp-r-inner-container {
|
||||
max-width: var(--max-width-onboarding-content);
|
||||
}
|
||||
|
||||
.ppcp-r-payment-method--separator {
|
||||
margin: 8px 0 24px 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,44 @@
|
|||
}
|
||||
|
||||
// Todo List and Feature Items
|
||||
.ppcp-r-todo-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ppcp-r-todo-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid $color-gray-300;
|
||||
padding-bottom: 16px;
|
||||
padding-top: 16px;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
&:first-child, &.is-dismissing:first-child + .ppcp-r-todo-item {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&:last-child,
|
||||
&:not(.is-dismissing):has(+ .is-dismissing:last-child) {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&.is-dismissing {
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
|
||||
.ppcp-r-todo-item__inner {
|
||||
height: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
@ -32,13 +64,25 @@
|
|||
}
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $color-gray-400;
|
||||
padding-bottom: 16px;
|
||||
&.is-completed {
|
||||
.ppcp-r-todo-item__icon {
|
||||
border-style: solid;
|
||||
background-color: $color-blueberry;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.dashicons {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
padding-top: 16px;
|
||||
.ppcp-r-todo-item__content {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
|
@ -47,17 +91,46 @@
|
|||
|
||||
&__inner {
|
||||
position: relative;
|
||||
height: auto;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
width: 100%;
|
||||
padding-right: 36px;
|
||||
transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
&__close {
|
||||
margin-left: auto;
|
||||
&__dismiss {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
color: $color-gray-400;
|
||||
border-radius: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
color: $color-blueberry;
|
||||
background-color: $color-gray-100;
|
||||
color: $color-gray-700;
|
||||
}
|
||||
|
||||
.dashicons {
|
||||
font-size: 14px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,36 +156,30 @@
|
|||
border-radius: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp-r-feature-item {
|
||||
padding-top: 32px;
|
||||
border-top: 1px solid $color-gray-400;
|
||||
.ppcp-r-tab-overview-features {
|
||||
--block-header-gap: 12px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include font(16, 20, 600);
|
||||
color: $color-black;
|
||||
display: block;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
.ppcp-r-tab-overview-help {
|
||||
--block-header-gap: 8px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
@include font(14, 20, 400);
|
||||
color: $color-gray-800;
|
||||
margin: 0 0 18px 0;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
.ppcp-r-settings-block__feature {
|
||||
.ppcp--action-buttons {
|
||||
display: flex;
|
||||
gap: 18px;
|
||||
|
||||
.components-button.is-tertiary {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__notes {
|
||||
.ppcp--item-notes {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
@ -166,3 +233,23 @@
|
|||
gap: 48px;
|
||||
}
|
||||
|
||||
.ppcp-highlight {
|
||||
animation: ppcp-highlight-fade 2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border: 1px solid $color-blueberry;
|
||||
border-radius: var(--container-border-radius);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes ppcp-highlight-fade {
|
||||
0%, 20% {
|
||||
background-color: rgba($color-blueberry, 0.08);
|
||||
border-color: $color-blueberry;
|
||||
border-width: 1px;
|
||||
}
|
||||
100% {
|
||||
background-color: transparent;
|
||||
border-color: $color-gray-300;
|
||||
border-width: 1px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ppcp-r-optional-payment-methods {
|
||||
&__wrapper {
|
||||
.ppcp-r-optional-payment-methods__wrapper {
|
||||
.ppcp-r-badge-box {
|
||||
margin: 0 0 24px 0;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -17,22 +17,20 @@
|
|||
|
||||
.ppcp-r-badge-box__description {
|
||||
margin: 12px 0 0 0;
|
||||
@include font(14, 20, 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__description {
|
||||
.ppcp-r-optional-payment-methods__description {
|
||||
@include font(14, 22, 400);
|
||||
margin: 32px 0 0 0;
|
||||
text-align: center;
|
||||
@include font(14, 22, 400);
|
||||
font-style: italic;
|
||||
|
||||
a {
|
||||
color: $color-gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
&__separator {
|
||||
margin: 0 0 24px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp-r-optional-payment-methods__separator {
|
||||
margin: 0 0 24px 0;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
@media screen and (max-width: 480px) {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 8px;
|
||||
|
||||
&__col {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
@ -77,7 +78,7 @@
|
|||
border-right: 0;
|
||||
padding-right: 0;
|
||||
padding-bottom: 8px;
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,3 +5,20 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
// Fix the checkbox layout (add gap between checkbox and label).
|
||||
.components-checkbox-control > .components-base-control__field > .components-flex {
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
// Fix layout for radio groups inside a horizontal flex-stack.
|
||||
.components-flex.components-h-stack > .components-radio-control {
|
||||
width: 100%;
|
||||
|
||||
.components-radio-control__group-wrapper {
|
||||
justify-content: flex-start;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.ppcp-r-paylater-configurator {
|
||||
display: flex;
|
||||
border: 1px solid var(--color-separators);
|
||||
border-radius: 8px;
|
||||
border-radius: var(--container-border-radius);
|
||||
overflow: hidden;
|
||||
font-family: "PayPalPro", sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
|
|
|
@ -7,3 +7,25 @@
|
|||
--block-header-gap: 0;
|
||||
--block-separator-size: 0;
|
||||
}
|
||||
|
||||
.ppcp--webhooks {
|
||||
.ppcp--webhook-list li {
|
||||
list-style: none;
|
||||
|
||||
&::before {
|
||||
content: '✔︎';
|
||||
opacity: 0.35;
|
||||
font-size: 0.75em;
|
||||
line-height: 1.35;
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ppcp--webhook-resubscribe,
|
||||
.ppcp--webhook-simulation {
|
||||
.ppcp--action .components-button {
|
||||
min-width: 160px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
display: flex;
|
||||
border: 1px solid var(--color-separators);
|
||||
border-radius: 8px;
|
||||
border-radius: var(--container-border-radius);
|
||||
|
||||
.ppcp-r-settings-block {
|
||||
&.header-section {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useMemo } from '@wordpress/element';
|
||||
import { useEffect, useMemo, useState } from '@wordpress/element';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { OnboardingHooks, CommonHooks } from '../data';
|
||||
|
@ -6,6 +6,7 @@ import SpinnerOverlay from './ReusableComponents/SpinnerOverlay';
|
|||
import SendOnlyMessage from './Screens/SendOnlyMessage';
|
||||
import OnboardingScreen from './Screens/Onboarding';
|
||||
import SettingsScreen from './Screens/Settings';
|
||||
import { getQuery } from '../utils/navigation';
|
||||
|
||||
const SettingsApp = () => {
|
||||
const { isReady: onboardingIsReady, completed: onboardingCompleted } =
|
||||
|
@ -31,6 +32,10 @@ const SettingsApp = () => {
|
|||
loading: ! onboardingIsReady,
|
||||
} );
|
||||
|
||||
const [ activePanel, setActivePanel ] = useState(
|
||||
getQuery().panel || 'overview'
|
||||
);
|
||||
|
||||
const Content = useMemo( () => {
|
||||
if ( ! onboardingIsReady || ! merchantIsReady ) {
|
||||
return <SpinnerOverlay />;
|
||||
|
@ -44,12 +49,18 @@ const SettingsApp = () => {
|
|||
return <OnboardingScreen />;
|
||||
}
|
||||
|
||||
return <SettingsScreen />;
|
||||
return (
|
||||
<SettingsScreen
|
||||
activePanel={ activePanel }
|
||||
setActivePanel={ setActivePanel }
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
isSendOnlyCountry,
|
||||
merchantIsReady,
|
||||
onboardingCompleted,
|
||||
onboardingIsReady,
|
||||
activePanel,
|
||||
] );
|
||||
|
||||
return <div className={ wrapperClass }>{ Content }</div>;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import data from '../../utils/data';
|
||||
import { LearnMore } from './Elements';
|
||||
import { PPIcon } from './Icons';
|
||||
|
||||
const ImageBadge = ( { images } ) => {
|
||||
if ( ! images || ! images.length ) {
|
||||
|
@ -8,13 +9,19 @@ const ImageBadge = ( { images } ) => {
|
|||
return (
|
||||
<BadgeContent>
|
||||
<span className="ppcp-r-badge-box__title-image-badge">
|
||||
{ images.map( ( badge ) => data().getImage( badge ) ) }
|
||||
{ images.map( ( badge, index ) => (
|
||||
<PPIcon
|
||||
key={ `badge-${ index }` }
|
||||
imageName={ badge }
|
||||
className="ppcp-r-badge-box__image"
|
||||
/>
|
||||
) ) }
|
||||
</span>
|
||||
</BadgeContent>
|
||||
);
|
||||
};
|
||||
|
||||
// If `children` is not empty, it's output and wrapped in spaces.
|
||||
// If `children` is not empty, the `children` prop is output and wrapped in spaces.
|
||||
const BadgeContent = ( { children } ) => {
|
||||
if ( ! children ) {
|
||||
return null;
|
||||
|
@ -22,22 +29,29 @@ const BadgeContent = ( { children } ) => {
|
|||
return <> { children } </>;
|
||||
};
|
||||
|
||||
const BadgeDescription = ( { description, learnMoreLink } ) => {
|
||||
if ( ! description && ! learnMoreLink ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-badge-box__description">
|
||||
<p className="ppcp-r-badge-box__description">
|
||||
{ description }
|
||||
<LearnMore url={ learnMoreLink } />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const BadgeBox = ( {
|
||||
title,
|
||||
textBadge,
|
||||
imageBadge = [],
|
||||
titleType = BADGE_BOX_TITLE_BIG,
|
||||
description = '',
|
||||
learnMoreLink = '',
|
||||
} ) => {
|
||||
let titleSize = BADGE_BOX_TITLE_SMALL;
|
||||
if ( BADGE_BOX_TITLE_BIG === titleType ) {
|
||||
titleSize = BADGE_BOX_TITLE_BIG;
|
||||
}
|
||||
|
||||
const titleTextClassName =
|
||||
'ppcp-r-badge-box__title-text ' +
|
||||
`ppcp-r-badge-box__title-text--${ titleSize }`;
|
||||
|
||||
const titleTextClassName = 'ppcp-r-badge-box__title-text';
|
||||
const titleBaseClassName = 'ppcp-r-badge-box__title';
|
||||
const titleClassName = imageBadge.length
|
||||
? `${ titleBaseClassName } ppcp-r-badge-box__title--has-image-badge`
|
||||
|
@ -51,20 +65,13 @@ const BadgeBox = ( {
|
|||
<ImageBadge images={ imageBadge } />
|
||||
<BadgeContent>{ textBadge }</BadgeContent>
|
||||
</span>
|
||||
<div className="ppcp-r-badge-box__description">
|
||||
{ description && (
|
||||
<p
|
||||
className="ppcp-r-badge-box__description"
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: description,
|
||||
} }
|
||||
></p>
|
||||
) }
|
||||
</div>
|
||||
|
||||
<BadgeDescription
|
||||
description={ description }
|
||||
learnMoreLink={ learnMoreLink }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const BADGE_BOX_TITLE_BIG = 'big';
|
||||
export const BADGE_BOX_TITLE_SMALL = 'small';
|
||||
export default BadgeBox;
|
||||
|
|
|
@ -9,7 +9,12 @@ const ControlButton = ( {
|
|||
buttonLabel,
|
||||
} ) => (
|
||||
<Action>
|
||||
<Button isBusy={ isBusy } variant={ type } onClick={ onClick }>
|
||||
<Button
|
||||
className="small-button"
|
||||
isBusy={ isBusy }
|
||||
variant={ type }
|
||||
onClick={ onClick }
|
||||
>
|
||||
{ buttonLabel }
|
||||
</Button>
|
||||
</Action>
|
||||
|
|
|
@ -10,6 +10,7 @@ const ControlTextInput = ( {
|
|||
} ) => (
|
||||
<Action>
|
||||
<TextControl
|
||||
__nextHasNoMarginBottom
|
||||
className="ppcp-r-vertical-text-control"
|
||||
placeholder={ placeholder }
|
||||
value={ value }
|
||||
|
|
|
@ -5,7 +5,7 @@ const ControlToggleButton = ( { label, description, value, onChange } ) => (
|
|||
<Action>
|
||||
<ToggleControl
|
||||
className="ppcp--control-toggle"
|
||||
__nextHasNoMarginBottom={ true }
|
||||
__nextHasNoMarginBottom
|
||||
checked={ value }
|
||||
onChange={ onChange }
|
||||
label={ label }
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import ControlTextInput from './ControlTextInput';
|
||||
|
||||
const SoftDescriptorInput = ( { value, onChange, placeholder } ) => {
|
||||
const handleChange = ( newValue ) => {
|
||||
if ( newValue.length <= 22 ) {
|
||||
onChange( newValue );
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ControlTextInput
|
||||
value={ value }
|
||||
onChange={ handleChange }
|
||||
placeholder={ placeholder }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SoftDescriptorInput;
|
|
@ -0,0 +1,16 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import { Button } from '@wordpress/components';
|
||||
|
||||
const LearnMore = ( { url } ) => {
|
||||
if ( ! url || '#' === url ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Button href={ url } variant="tertiary" target="_blank">
|
||||
{ __( 'Learn more', 'woocommerce-paypal-payments' ) }
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default LearnMore;
|
|
@ -7,7 +7,8 @@ export { default as Content } from './Content';
|
|||
export { default as ContentWrapper } from './ContentWrapper';
|
||||
export { default as Description } from './Description';
|
||||
export { default as Header } from './Header';
|
||||
export { default as LearnMore } from './LearnMore';
|
||||
export { default as Separator } from './Separator';
|
||||
export { default as Title } from './Title';
|
||||
export { default as TitleExtra } from './TitleExtra';
|
||||
export { default as TitleWrapper } from './TitleWrapper';
|
||||
export { default as Separator } from './Separator';
|
||||
|
|
|
@ -24,6 +24,7 @@ const Checkbox = ( {
|
|||
|
||||
return (
|
||||
<CheckboxControl
|
||||
__nextHasNoMarginBottom={ true }
|
||||
label={ label }
|
||||
value={ value }
|
||||
checked={ checked }
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import { PayPalCheckbox } from './index';
|
||||
import { useCallback } from '@wordpress/element';
|
||||
|
||||
const CheckboxGroup = ( { options, value, onChange } ) => {
|
||||
const handleChange = ( key, checked ) => {
|
||||
const CheckboxGroup = ( { name, options, value, onChange } ) => {
|
||||
const handleChange = useCallback(
|
||||
( key, checked ) => {
|
||||
const getNewValue = () => {
|
||||
if ( 'boolean' === typeof value ) {
|
||||
return checked;
|
||||
}
|
||||
|
||||
if ( checked ) {
|
||||
return [ ...value, key ];
|
||||
}
|
||||
|
@ -10,6 +16,24 @@ const CheckboxGroup = ( { options, value, onChange } ) => {
|
|||
};
|
||||
|
||||
onChange( getNewValue() );
|
||||
},
|
||||
[ onChange, value ]
|
||||
);
|
||||
|
||||
const isItemChecked = ( checked, itemValue ) => {
|
||||
if ( typeof checked === 'boolean' ) {
|
||||
return checked;
|
||||
}
|
||||
|
||||
if ( Array.isArray( value ) ) {
|
||||
return value.includes( itemValue );
|
||||
}
|
||||
|
||||
if ( typeof value === 'boolean' ) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return value === itemValue;
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -21,16 +45,14 @@ const CheckboxGroup = ( { options, value, onChange } ) => {
|
|||
checked,
|
||||
disabled,
|
||||
description,
|
||||
tooltip,
|
||||
} ) => (
|
||||
<PayPalCheckbox
|
||||
key={ itemValue }
|
||||
key={ name + itemValue }
|
||||
value={ itemValue }
|
||||
label={ label }
|
||||
checked={ checked }
|
||||
checked={ isItemChecked( checked, itemValue ) }
|
||||
disabled={ disabled }
|
||||
description={ description }
|
||||
tooltip={ tooltip }
|
||||
changeCallback={ handleChange }
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -49,10 +49,12 @@ const OptionItem = ( {
|
|||
} ) => {
|
||||
const boxClassName = classNames( 'ppcp-r-select-box', {
|
||||
'ppcp--selected': isSelected,
|
||||
'ppcp--multiselect': isMulti,
|
||||
} );
|
||||
|
||||
return (
|
||||
<div className={ boxClassName }>
|
||||
// eslint-disable-next-line jsx-a11y/label-has-associated-control -- label has a nested input control.
|
||||
<label className={ boxClassName }>
|
||||
<InputField
|
||||
value={ itemValue }
|
||||
isRadio={ ! isMulti }
|
||||
|
@ -60,22 +62,18 @@ const OptionItem = ( {
|
|||
isSelected={ isSelected }
|
||||
/>
|
||||
|
||||
<div className="ppcp-r-select-box__content">
|
||||
<div className="ppcp-r-select-box__content-inner">
|
||||
<span className="ppcp-r-select-box__title">
|
||||
{ itemTitle }
|
||||
</span>
|
||||
<p className="ppcp-r-select-box__description">
|
||||
<div className="ppcp--box-content">
|
||||
<div className="ppcp--box-content-inner">
|
||||
<span className="ppcp--box-title">{ itemTitle }</span>
|
||||
<div className="ppcp--box-description">
|
||||
{ itemDescription }
|
||||
</p>
|
||||
{ children && (
|
||||
<div className="ppcp-r-select-box__additional-content">
|
||||
{ children }
|
||||
</div>
|
||||
{ children && (
|
||||
<div className="ppcp--box-details">{ children }</div>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* Temporary component, until the experimental HStack block editor component is stable.
|
||||
*
|
||||
* @see https://wordpress.github.io/gutenberg/?path=/docs/components-experimental-hstack--docs
|
||||
* @file
|
||||
*/
|
||||
import classNames from 'classnames';
|
||||
|
||||
const HStack = ( { className, spacing = 3, children } ) => {
|
||||
const wrapperClass = classNames(
|
||||
'components-flex components-h-stack',
|
||||
className
|
||||
);
|
||||
|
||||
const styles = {
|
||||
gap: `calc(${ 4 * spacing }px)`,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={ wrapperClass } style={ styles }>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HStack;
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
|
||||
const GenericIcon = ( { imageName, className = '', alt = '' } ) => {
|
||||
const pathToImages = global.ppcpSettings.assets.imagesUrl;
|
||||
|
||||
return (
|
||||
<img
|
||||
className={ className }
|
||||
alt={ alt }
|
||||
src={ `${ pathToImages }${ imageName }` }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default GenericIcon;
|
|
@ -1,6 +1,6 @@
|
|||
import { SVG, Path } from '@wordpress/primitives';
|
||||
|
||||
const logoPayPal = (
|
||||
const LogoPayPal = (
|
||||
<SVG fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 110 38">
|
||||
<Path
|
||||
d="M109.583.683v27.359h-6.225V.683h6.225Zm-8.516 9.234v18.175h-5.534v-1.567c-.7.683-1.5 1.2-2.383 1.567a7.259 7.259 0 0 1-2.892.583c-1.3 0-2.508-.242-3.616-.725a9.216 9.216 0 0 1-2.892-2.067 10.021 10.021 0 0 1-1.958-3.05c-.459-1.183-.684-2.458-.684-3.816 0-1.359.225-2.617.684-3.775.483-1.184 1.133-2.217 1.958-3.092a8.708 8.708 0 0 1 2.892-2.033c1.108-.509 2.316-.767 3.616-.767 1.034 0 2 .192 2.892.583a7.312 7.312 0 0 1 2.383 1.567V9.933h5.534v-.016Zm-9.809 13.225c1.134 0 2.059-.384 2.784-1.167.75-.775 1.125-1.767 1.125-2.975 0-1.208-.375-2.208-1.125-2.975-.725-.775-1.659-1.167-2.784-1.167-1.125 0-2.075.384-2.825 1.167-.725.775-1.083 1.767-1.083 2.975 0 1.208.367 2.208 1.083 2.975.75.775 1.692 1.167 2.825 1.167ZM72.225.683c1.642 0 3.042.234 4.2.692 1.158.458 2.133 1.1 2.933 1.925a9.439 9.439 0 0 1 1.917 2.908c.458 1.092.683 2.267.683 3.525 0 1.259-.225 2.434-.683 3.525a9.293 9.293 0 0 1-1.917 2.909c-.791.825-1.775 1.466-2.933 1.925-1.158.458-2.558.691-4.2.691h-3v9.3h-6.333V.683h9.333Zm-.908 12.467c.85 0 1.491-.083 1.958-.258a3.853 3.853 0 0 0 1.192-.725c.65-.609.975-1.417.975-2.434 0-1.016-.325-1.825-.975-2.433a3.329 3.329 0 0 0-1.192-.692c-.458-.191-1.108-.291-1.958-.291h-2.1v6.833h2.1ZM39.558 9.917h6.875l4.667 8.716h.075l4.158-8.716H61.7l-13.642 27.4h-6.333l6.225-12.534-8.392-14.866Zm-1.225 0v18.175H32.8v-1.567c-.7.683-1.5 1.2-2.383 1.567a7.258 7.258 0 0 1-2.892.583c-1.3 0-2.508-.242-3.617-.725a9.218 9.218 0 0 1-2.891-2.067 10.18 10.18 0 0 1-1.959-3.05c-.458-1.183-.683-2.458-.683-3.816 0-1.359.225-2.617.683-3.775.484-1.184 1.134-2.217 1.959-3.092a8.626 8.626 0 0 1 2.891-2.033c1.109-.509 2.317-.767 3.617-.767 1.033 0 2 .192 2.892.583A7.312 7.312 0 0 1 32.8 11.5V9.933h5.533v-.016Zm-9.808 13.225c1.133 0 2.058-.384 2.792-1.167.75-.775 1.125-1.767 1.125-2.975 0-1.208-.375-2.208-1.125-2.975-.725-.775-1.659-1.167-2.792-1.167-1.133 0-2.075.384-2.825 1.167-.725.775-1.083 1.767-1.083 2.975 0 1.208.366 2.208 1.083 2.975.75.775 1.692 1.167 2.825 1.167ZM9.75.683c1.642 0 3.042.234 4.2.692 1.158.458 2.133 1.1 2.933 1.925A9.439 9.439 0 0 1 18.8 6.208c.458 1.092.683 2.267.683 3.525 0 1.259-.225 2.434-.683 3.525a9.293 9.293 0 0 1-1.917 2.909c-.791.825-1.775 1.466-2.933 1.925-1.158.458-2.558.691-4.2.691h-3v9.3H.417V.683H9.75Zm-.9 12.467c.85 0 1.492-.083 1.958-.258A3.855 3.855 0 0 0 12 12.167c.65-.609.975-1.417.975-2.434 0-1.016-.325-1.825-.975-2.433a3.33 3.33 0 0 0-1.192-.692c-.458-.191-1.108-.291-1.958-.291h-2.1v6.833h2.1Z"
|
||||
|
@ -9,4 +9,4 @@ const logoPayPal = (
|
|||
</SVG>
|
||||
);
|
||||
|
||||
export default logoPayPal;
|
||||
export default LogoPayPal;
|
|
@ -1,9 +1,9 @@
|
|||
import { SVG, Path } from '@wordpress/primitives';
|
||||
|
||||
const openSignup = (
|
||||
const OpenSignup = (
|
||||
<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 24">
|
||||
<Path d="M12.4999 12.75V18.75C12.4999 18.9489 12.4209 19.1397 12.2803 19.2803C12.1396 19.421 11.9488 19.5 11.7499 19.5C11.551 19.5 11.3603 19.421 11.2196 19.2803C11.0789 19.1397 10.9999 18.9489 10.9999 18.75V14.5613L4.78055 20.7806C4.71087 20.8503 4.62815 20.9056 4.5371 20.9433C4.44606 20.981 4.34847 21.0004 4.24993 21.0004C4.15138 21.0004 4.0538 20.981 3.96276 20.9433C3.87171 20.9056 3.78899 20.8503 3.7193 20.7806C3.64962 20.7109 3.59435 20.6282 3.55663 20.5372C3.51892 20.4461 3.49951 20.3485 3.49951 20.25C3.49951 20.1515 3.51892 20.0539 3.55663 19.9628C3.59435 19.8718 3.64962 19.7891 3.7193 19.7194L9.93868 13.5H5.74993C5.55102 13.5 5.36025 13.421 5.2196 13.2803C5.07895 13.1397 4.99993 12.9489 4.99993 12.75C4.99993 12.5511 5.07895 12.3603 5.2196 12.2197C5.36025 12.079 5.55102 12 5.74993 12H11.7499C11.9488 12 12.1396 12.079 12.2803 12.2197C12.4209 12.3603 12.4999 12.5511 12.4999 12.75ZM19.9999 3H7.99993C7.6021 3 7.22057 3.15804 6.93927 3.43934C6.65796 3.72064 6.49993 4.10218 6.49993 4.5V9C6.49993 9.19891 6.57895 9.38968 6.7196 9.53033C6.86025 9.67098 7.05102 9.75 7.24993 9.75C7.44884 9.75 7.63961 9.67098 7.78026 9.53033C7.92091 9.38968 7.99993 9.19891 7.99993 9V4.5H19.9999V16.5H15.4999C15.301 16.5 15.1103 16.579 14.9696 16.7197C14.8289 16.8603 14.7499 17.0511 14.7499 17.25C14.7499 17.4489 14.8289 17.6397 14.9696 17.7803C15.1103 17.921 15.301 18 15.4999 18H19.9999C20.3978 18 20.7793 17.842 21.0606 17.5607C21.3419 17.2794 21.4999 16.8978 21.4999 16.5V4.5C21.4999 4.10218 21.3419 3.72064 21.0606 3.43934C20.7793 3.15804 20.3978 3 19.9999 3Z" />
|
||||
</SVG>
|
||||
);
|
||||
|
||||
export default openSignup;
|
||||
export default OpenSignup;
|
|
@ -1,5 +1,6 @@
|
|||
export { default as openSignup } from './open-signup';
|
||||
export { default as logoPayPal } from './logo-paypal';
|
||||
export { default as PPIcon } from './GenericIcon';
|
||||
export { default as OpenSignup } from './OpenSignup';
|
||||
export { default as LogoPayPal } from './LogoPayPal';
|
||||
|
||||
export const NOTIFICATION_SUCCESS = '✔️';
|
||||
export const NOTIFICATION_ERROR = '❌';
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
import { Icon } from '@wordpress/components';
|
||||
|
||||
import data from '../../utils/data';
|
||||
|
||||
const PaymentMethodIcon = ( props ) => {
|
||||
if (
|
||||
( Array.isArray( props.icons ) &&
|
||||
props.icons.includes( props.type ) ) ||
|
||||
props.icons === 'all'
|
||||
) {
|
||||
return data().getImage( 'icon-button-' + props.type + '.svg' );
|
||||
const PaymentMethodIcon = ( { icons, type } ) => {
|
||||
const validIcon = Array.isArray( icons ) && icons.includes( type );
|
||||
|
||||
if ( validIcon || icons === 'all' ) {
|
||||
return (
|
||||
<Icon
|
||||
icon={ data().getImage( 'icon-button-' + type + '.svg' ) }
|
||||
className="ppcp--method-icon"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <></>;
|
||||
return null;
|
||||
};
|
||||
|
||||
export default PaymentMethodIcon;
|
||||
|
|
|
@ -2,6 +2,7 @@ import classNames from 'classnames';
|
|||
import { Description, Header, Title, TitleExtra, Content } from './Elements';
|
||||
|
||||
const SettingsBlock = ( {
|
||||
id,
|
||||
className,
|
||||
children,
|
||||
title,
|
||||
|
@ -15,7 +16,26 @@ const SettingsBlock = ( {
|
|||
'ppcp--horizontal': horizontalLayout,
|
||||
} );
|
||||
|
||||
const BlockTitle = ( { blockTitle, blockSuffix, blockDescription } ) => {
|
||||
const props = {
|
||||
className: blockClassName,
|
||||
...( id && { id } ),
|
||||
};
|
||||
|
||||
return (
|
||||
<div { ...props }>
|
||||
<BlockTitle
|
||||
blockTitle={ title }
|
||||
blockSuffix={ titleSuffix }
|
||||
blockDescription={ description }
|
||||
/>
|
||||
<Content asCard={ false }>{ children }</Content>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsBlock;
|
||||
|
||||
const BlockTitle = ( { blockTitle, blockSuffix, blockDescription } ) => {
|
||||
if ( ! blockTitle && ! blockDescription ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -29,19 +49,4 @@ const SettingsBlock = ( {
|
|||
<Description>{ blockDescription }</Description>
|
||||
</Header>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={ blockClassName }>
|
||||
<BlockTitle
|
||||
blockTitle={ title }
|
||||
blockSuffix={ titleSuffix }
|
||||
blockDescription={ description }
|
||||
/>
|
||||
|
||||
<Content asCard={ false }>{ children }</Content>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsBlock;
|
||||
|
|
|
@ -12,7 +12,7 @@ const FeatureSettingsBlock = ( { title, description, ...props } ) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<span className="ppcp-r-feature-item__notes">
|
||||
<span className="ppcp--item-notes">
|
||||
{ notes.map( ( note, index ) => (
|
||||
<span key={ index }>{ note }</span>
|
||||
) ) }
|
||||
|
@ -20,6 +20,32 @@ const FeatureSettingsBlock = ( { title, description, ...props } ) => {
|
|||
);
|
||||
};
|
||||
|
||||
const FeatureButton = ( {
|
||||
className,
|
||||
variant,
|
||||
text,
|
||||
isBusy,
|
||||
url,
|
||||
urls,
|
||||
onClick,
|
||||
} ) => {
|
||||
const buttonProps = {
|
||||
className,
|
||||
isBusy,
|
||||
variant,
|
||||
};
|
||||
|
||||
if ( url || urls ) {
|
||||
buttonProps.href = urls ? urls.live : url;
|
||||
buttonProps.target = '_blank';
|
||||
}
|
||||
if ( ! buttonProps.href ) {
|
||||
buttonProps.onClick = onClick;
|
||||
}
|
||||
|
||||
return <Button { ...buttonProps }>{ text }</Button>;
|
||||
};
|
||||
|
||||
const renderDescription = () => {
|
||||
return (
|
||||
<span
|
||||
|
@ -29,32 +55,6 @@ const FeatureSettingsBlock = ( { title, description, ...props } ) => {
|
|||
);
|
||||
};
|
||||
|
||||
const renderButton = ( button ) => {
|
||||
const buttonElement = (
|
||||
<Button
|
||||
className={ button.class ? button.class : '' }
|
||||
key={ button.text }
|
||||
isBusy={ props.actionProps?.isBusy }
|
||||
variant={ button.type }
|
||||
onClick={ button.onClick }
|
||||
>
|
||||
{ button.text }
|
||||
</Button>
|
||||
);
|
||||
|
||||
// If there's a URL (either direct or in urls object), wrap in anchor tag
|
||||
if ( button.url || button.urls ) {
|
||||
const href = button.urls ? button.urls.live : button.url;
|
||||
return (
|
||||
<a href={ href } key={ button.text }>
|
||||
{ buttonElement }
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return buttonElement;
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsBlock { ...props } className="ppcp-r-settings-block__feature">
|
||||
<Header>
|
||||
|
@ -70,8 +70,28 @@ const FeatureSettingsBlock = ( { title, description, ...props } ) => {
|
|||
</Description>
|
||||
</Header>
|
||||
<Action>
|
||||
<div className="ppcp-r-feature-item__buttons">
|
||||
{ props.actionProps?.buttons.map( renderButton ) }
|
||||
<div className="ppcp--action-buttons">
|
||||
{ props.actionProps?.buttons.map(
|
||||
( {
|
||||
class: className,
|
||||
type,
|
||||
text,
|
||||
url,
|
||||
urls,
|
||||
onClick,
|
||||
} ) => (
|
||||
<FeatureButton
|
||||
key={ text }
|
||||
className={ className }
|
||||
variant={ type }
|
||||
text={ text }
|
||||
isBusy={ props.actionProps.isBusy }
|
||||
url={ url }
|
||||
urls={ urls }
|
||||
onClick={ onClick }
|
||||
/>
|
||||
)
|
||||
) }
|
||||
</div>
|
||||
</Action>
|
||||
</SettingsBlock>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { ToggleControl } from '@wordpress/components';
|
||||
import { ToggleControl, Icon, Button } from '@wordpress/components';
|
||||
import { cog } from '@wordpress/icons';
|
||||
import { useEffect } from '@wordpress/element';
|
||||
import { useActiveHighlight } from '../../../data/common/hooks';
|
||||
|
||||
import SettingsBlock from '../SettingsBlock';
|
||||
import PaymentMethodIcon from '../PaymentMethodIcon';
|
||||
import data from '../../../utils/data';
|
||||
|
||||
const PaymentMethodItemBlock = ( {
|
||||
paymentMethod,
|
||||
|
@ -10,34 +12,56 @@ const PaymentMethodItemBlock = ( {
|
|||
onSelect,
|
||||
isSelected,
|
||||
} ) => {
|
||||
const { activeHighlight, setActiveHighlight } = useActiveHighlight();
|
||||
const isHighlighted = activeHighlight === paymentMethod.id;
|
||||
|
||||
// Reset the active highlight after 2 seconds
|
||||
useEffect( () => {
|
||||
if ( isHighlighted ) {
|
||||
const timer = setTimeout( () => {
|
||||
setActiveHighlight( null );
|
||||
}, 2000 );
|
||||
|
||||
return () => clearTimeout( timer );
|
||||
}
|
||||
}, [ isHighlighted, setActiveHighlight ] );
|
||||
|
||||
return (
|
||||
<SettingsBlock className="ppcp-r-settings-block__payment-methods__item">
|
||||
<div className="ppcp-r-settings-block__payment-methods__item__inner">
|
||||
<div className="ppcp-r-settings-block__payment-methods__item__title-wrapper">
|
||||
<SettingsBlock
|
||||
id={ paymentMethod.id }
|
||||
className={ `ppcp--method-item ${
|
||||
isHighlighted ? 'ppcp-highlight' : ''
|
||||
}` }
|
||||
separatorAndGap={ false }
|
||||
>
|
||||
<div className="ppcp--method-inner">
|
||||
<div className="ppcp--method-title-wrapper">
|
||||
{ paymentMethod?.icon && (
|
||||
<PaymentMethodIcon
|
||||
icons={ [ paymentMethod.icon ] }
|
||||
type={ paymentMethod.icon }
|
||||
/>
|
||||
<span className="ppcp-r-settings-block__payment-methods__item__title">
|
||||
) }
|
||||
<span className="ppcp--method-title">
|
||||
{ paymentMethod.itemTitle }
|
||||
</span>
|
||||
</div>
|
||||
<p className="ppcp-r-settings-block__payment-methods__item__description">
|
||||
<p className="ppcp--method-description">
|
||||
{ paymentMethod.itemDescription }
|
||||
</p>
|
||||
<div className="ppcp-r-settings-block__payment-methods__item__footer">
|
||||
<div className="ppcp--method-footer">
|
||||
<ToggleControl
|
||||
__nextHasNoMarginBottom={ true }
|
||||
__nextHasNoMarginBottom
|
||||
checked={ isSelected }
|
||||
onChange={ onSelect }
|
||||
/>
|
||||
{ paymentMethod?.fields && onTriggerModal && (
|
||||
<div
|
||||
className="ppcp-r-settings-block__payment-methods__item__settings"
|
||||
<Button
|
||||
className="ppcp--method-settings"
|
||||
onClick={ onTriggerModal }
|
||||
>
|
||||
{ data().getImage( 'icon-settings.svg' ) }
|
||||
</div>
|
||||
<Icon icon={ cog } />
|
||||
</Button>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,36 +1,32 @@
|
|||
import SettingsBlock from '../SettingsBlock';
|
||||
import PaymentMethodItemBlock from './PaymentMethodItemBlock';
|
||||
import { usePaymentMethods } from '../../../data/payment/hooks';
|
||||
import { PaymentHooks } from '../../../data';
|
||||
|
||||
const PaymentMethodsBlock = ( {
|
||||
paymentMethods,
|
||||
className = '',
|
||||
onTriggerModal,
|
||||
} ) => {
|
||||
const { setPersistent } = usePaymentMethods();
|
||||
// TODO: This is not a reusable component, as it's connected to the Redux store.
|
||||
const PaymentMethodsBlock = ( { paymentMethods = [], onTriggerModal } ) => {
|
||||
const { changePaymentSettings } = PaymentHooks.useStore();
|
||||
|
||||
if ( ! paymentMethods?.length ) {
|
||||
const handleSelect = ( methodId, isSelected ) =>
|
||||
changePaymentSettings( methodId, {
|
||||
enabled: isSelected,
|
||||
} );
|
||||
|
||||
if ( ! paymentMethods.length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleSelect = ( paymentMethod, isSelected ) => {
|
||||
setPersistent( paymentMethod.id, {
|
||||
...paymentMethod,
|
||||
enabled: isSelected,
|
||||
} );
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsBlock
|
||||
className={ `ppcp-r-settings-block__payment-methods ${ className }` }
|
||||
>
|
||||
{ paymentMethods.map( ( paymentMethod ) => (
|
||||
<SettingsBlock className="ppcp--grid ppcp-r-settings-block__payment-methods">
|
||||
{ paymentMethods
|
||||
// Remove empty/invalid payment method entries.
|
||||
.filter( ( m ) => m.id )
|
||||
.map( ( paymentMethod ) => (
|
||||
<PaymentMethodItemBlock
|
||||
key={ paymentMethod.id }
|
||||
paymentMethod={ paymentMethod }
|
||||
isSelected={ paymentMethod.enabled }
|
||||
onSelect={ ( checked ) =>
|
||||
handleSelect( paymentMethod, checked )
|
||||
handleSelect( paymentMethod.id, checked )
|
||||
}
|
||||
onTriggerModal={ () =>
|
||||
onTriggerModal?.( paymentMethod.id )
|
||||
|
|
|
@ -1,36 +1,131 @@
|
|||
const TodoSettingsBlock = ( { todosData, className = '' } ) => {
|
||||
import { selectTab, TAB_IDS } from '../../../utils/tabSelector';
|
||||
import { useEffect, useState } from '@wordpress/element';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { STORE_NAME as TODOS_STORE_NAME } from '../../../data/todos';
|
||||
|
||||
const TodoSettingsBlock = ( {
|
||||
todosData,
|
||||
className = '',
|
||||
setActiveModal,
|
||||
setActiveHighlight,
|
||||
onDismissTodo,
|
||||
} ) => {
|
||||
const [ dismissingIds, setDismissingIds ] = useState( new Set() );
|
||||
const { completedTodos, dismissedTodos } = useSelect(
|
||||
( select ) => ( {
|
||||
completedTodos:
|
||||
select( TODOS_STORE_NAME ).getCompletedTodos() || [],
|
||||
dismissedTodos:
|
||||
select( TODOS_STORE_NAME ).getDismissedTodos() || [],
|
||||
} ),
|
||||
[]
|
||||
);
|
||||
|
||||
const { completeOnClick } = useDispatch( TODOS_STORE_NAME );
|
||||
|
||||
useEffect( () => {
|
||||
if ( dismissedTodos.length === 0 ) {
|
||||
setDismissingIds( new Set() );
|
||||
}
|
||||
}, [ dismissedTodos ] );
|
||||
|
||||
if ( todosData.length === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleDismiss = ( todoId, e ) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDismissingIds( ( prev ) => new Set( [ ...prev, todoId ] ) );
|
||||
|
||||
setTimeout( () => {
|
||||
onDismissTodo( todoId );
|
||||
}, 300 );
|
||||
};
|
||||
|
||||
const handleClick = async ( todo ) => {
|
||||
if ( todo.action.type === 'tab' ) {
|
||||
const tabId = TAB_IDS[ todo.action.tab.toUpperCase() ];
|
||||
await selectTab( tabId, todo.action.section );
|
||||
} else if ( todo.action.type === 'external' ) {
|
||||
window.open( todo.action.url, '_blank' );
|
||||
// If it has completeOnClick flag, trigger the action
|
||||
if ( todo.action.completeOnClick === true ) {
|
||||
await completeOnClick( todo.id );
|
||||
}
|
||||
}
|
||||
|
||||
if ( todo.action.modal ) {
|
||||
setActiveModal( todo.action.modal );
|
||||
}
|
||||
if ( todo.action.highlight ) {
|
||||
setActiveHighlight( todo.action.highlight );
|
||||
}
|
||||
};
|
||||
|
||||
// Filter out dismissed todos for display
|
||||
const visibleTodos = todosData.filter(
|
||||
( todo ) => ! dismissedTodos.includes( todo.id )
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ `ppcp-r-settings-block__todo ppcp-r-todo-items ${ className }` }
|
||||
>
|
||||
{ todosData
|
||||
.slice( 0, 5 )
|
||||
.filter( ( todo ) => {
|
||||
return ! todo.isCompleted();
|
||||
} )
|
||||
.map( ( todo ) => (
|
||||
{ visibleTodos.map( ( todo ) => (
|
||||
<TodoItem
|
||||
key={ todo.id }
|
||||
id={ todo.id }
|
||||
title={ todo.title }
|
||||
onClick={ todo.onClick }
|
||||
description={ todo.description }
|
||||
isCompleted={ completedTodos.includes( todo.id ) }
|
||||
isDismissing={ dismissingIds.has( todo.id ) }
|
||||
onDismiss={ ( e ) => handleDismiss( todo.id, e ) }
|
||||
onClick={ () => handleClick( todo ) }
|
||||
/>
|
||||
) ) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TodoItem = ( props ) => {
|
||||
const TodoItem = ( {
|
||||
title,
|
||||
description,
|
||||
isCompleted,
|
||||
isDismissing,
|
||||
onClick,
|
||||
onDismiss,
|
||||
} ) => {
|
||||
return (
|
||||
<div className="ppcp-r-todo-item" onClick={ props.onClick }>
|
||||
<div
|
||||
className={ `ppcp-r-todo-item ${
|
||||
isCompleted ? 'is-completed' : ''
|
||||
} ${ isDismissing ? 'is-dismissing' : '' }` }
|
||||
onClick={ onClick }
|
||||
>
|
||||
<div className="ppcp-r-todo-item__inner">
|
||||
<div className="ppcp-r-todo-item__icon"></div>
|
||||
<div className="ppcp-r-todo-item__description">
|
||||
{ props.title }
|
||||
<div className="ppcp-r-todo-item__icon">
|
||||
{ isCompleted && (
|
||||
<span className="dashicons dashicons-yes"></span>
|
||||
) }
|
||||
</div>
|
||||
<div className="ppcp-r-todo-item__content">
|
||||
<div className="ppcp-r-todo-item__description">
|
||||
{ title }
|
||||
</div>
|
||||
{ description && (
|
||||
<div className="ppcp-r-todo-item__secondary-description">
|
||||
{ description }
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
<button
|
||||
className="ppcp-r-todo-item__dismiss"
|
||||
onClick={ onDismiss }
|
||||
aria-label="Dismiss todo item"
|
||||
>
|
||||
<span className="dashicons dashicons-no-alt"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,55 +1,47 @@
|
|||
import classNames from 'classnames';
|
||||
|
||||
import { Content, ContentWrapper } from './Elements';
|
||||
import { Content } from './Elements';
|
||||
|
||||
const SettingsCard = ( {
|
||||
id,
|
||||
className: extraClassName,
|
||||
className,
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
contentItems,
|
||||
contentContainer = true,
|
||||
} ) => {
|
||||
const className = classNames( 'ppcp-r-settings-card', extraClassName );
|
||||
|
||||
const renderContent = () => {
|
||||
// If contentItems array is provided, wrap each item in Content component
|
||||
if ( contentItems ) {
|
||||
return (
|
||||
<ContentWrapper>
|
||||
{ contentItems.map( ( item ) => (
|
||||
<Content key={ item.key } id={ item.key }>
|
||||
{ item }
|
||||
</Content>
|
||||
) ) }
|
||||
</ContentWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise handle regular children with contentContainer prop
|
||||
if ( contentContainer ) {
|
||||
return <Content>{ children }</Content>;
|
||||
}
|
||||
|
||||
return children;
|
||||
const cardClassNames = classNames( 'ppcp-r-settings-card', className );
|
||||
const cardProps = {
|
||||
className: cardClassNames,
|
||||
id,
|
||||
};
|
||||
|
||||
return (
|
||||
<div id={ id } className={ className }>
|
||||
<div { ...cardProps }>
|
||||
<div className="ppcp-r-settings-card__header">
|
||||
<div className="ppcp-r-settings-card__content-inner">
|
||||
<span className="ppcp-r-settings-card__title">
|
||||
{ title }
|
||||
</span>
|
||||
<p className="ppcp-r-settings-card__description">
|
||||
<div className="ppcp-r-settings-card__description">
|
||||
{ description }
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{ renderContent() }
|
||||
</div>
|
||||
|
||||
<InnerContent showCards={ contentContainer }>
|
||||
{ children }
|
||||
</InnerContent>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsCard;
|
||||
|
||||
const InnerContent = ( { showCards, children } ) => {
|
||||
if ( showCards ) {
|
||||
return <Content>{ children }</Content>;
|
||||
}
|
||||
|
||||
return children;
|
||||
};
|
||||
|
|
|
@ -43,6 +43,7 @@ const SettingsToggleBlock = ( {
|
|||
</div>
|
||||
<div className="ppcp-r-toggle-block__switch">
|
||||
<ToggleControl
|
||||
__nextHasNoMarginBottom
|
||||
ref={ toggleRef }
|
||||
checked={ isToggled }
|
||||
onChange={ ( newState ) => setToggled( newState ) }
|
||||
|
|
|
@ -9,9 +9,7 @@ const SpinnerOverlay = ( { message = null } ) => {
|
|||
return (
|
||||
<div className="ppcp-r-spinner-overlay">
|
||||
{ message && (
|
||||
<span className="ppcp-r-spinner-overlay__message">
|
||||
{ message }
|
||||
</span>
|
||||
<span className="ppcp--spinner-message">{ message }</span>
|
||||
) }
|
||||
<Spinner />
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Temporary component, until the experimental VStack/HStack block editor component is stable.
|
||||
*
|
||||
* @see https://wordpress.github.io/gutenberg/?path=/docs/components-experimental-hstack--docs
|
||||
* @see https://wordpress.github.io/gutenberg/?path=/docs/components-experimental-vstack--docs
|
||||
* @file
|
||||
*/
|
||||
import classNames from 'classnames';
|
||||
|
||||
const Stack = ( { type, className, spacing, children } ) => {
|
||||
const wrapperClass = classNames(
|
||||
'components-flex',
|
||||
`components-${ type }-stack`,
|
||||
className
|
||||
);
|
||||
|
||||
const styles = {
|
||||
gap: `calc(${ 4 * spacing }px)`,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={ wrapperClass } style={ styles }>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const HStack = ( { className, spacing = 3, children } ) => {
|
||||
return (
|
||||
<Stack type="h" className={ className } spacing={ spacing }>
|
||||
{ children }
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export const VStack = ( { className, spacing = 3, children } ) => {
|
||||
return (
|
||||
<Stack type="v" className={ className } spacing={ spacing }>
|
||||
{ children }
|
||||
</Stack>
|
||||
);
|
||||
};
|
|
@ -1,26 +1,14 @@
|
|||
import { useCallback, useEffect, useState } from '@wordpress/element';
|
||||
import { useCallback, useEffect } from '@wordpress/element';
|
||||
|
||||
// TODO: Migrate to Tabs (TabPanel v2) once its API is publicly available, as it provides programmatic tab switching support: https://github.com/WordPress/gutenberg/issues/52997
|
||||
import { TabPanel } from '@wordpress/components';
|
||||
|
||||
import { getQuery, updateQueryString } from '../../utils/navigation';
|
||||
|
||||
const TabNavigation = ( { tabs } ) => {
|
||||
const { panel } = getQuery();
|
||||
import { updateQueryString } from '../../utils/navigation';
|
||||
|
||||
const TabBar = ( { tabs, activePanel, setActivePanel } ) => {
|
||||
const isValidTab = ( tabsList, checkTab ) => {
|
||||
return tabsList.some( ( tab ) => tab.name === checkTab );
|
||||
};
|
||||
|
||||
const getValidInitialPanel = () => {
|
||||
if ( ! panel || ! isValidTab( tabs, panel ) ) {
|
||||
return tabs[ 0 ].name;
|
||||
}
|
||||
return panel;
|
||||
};
|
||||
|
||||
const [ activePanel, setActivePanel ] = useState( getValidInitialPanel );
|
||||
|
||||
const updateActivePanel = useCallback(
|
||||
( tabName ) => {
|
||||
if ( isValidTab( tabs, tabName ) ) {
|
||||
|
@ -29,7 +17,7 @@ const TabNavigation = ( { tabs } ) => {
|
|||
console.warn( `Invalid tab name: ${ tabName }` );
|
||||
}
|
||||
},
|
||||
[ tabs ]
|
||||
[ tabs, setActivePanel ]
|
||||
);
|
||||
|
||||
useEffect( () => {
|
||||
|
@ -43,9 +31,9 @@ const TabNavigation = ( { tabs } ) => {
|
|||
onSelect={ updateActivePanel }
|
||||
tabs={ tabs }
|
||||
>
|
||||
{ ( { Component } ) => Component }
|
||||
{ () => '' }
|
||||
</TabPanel>
|
||||
);
|
||||
};
|
||||
|
||||
export default TabNavigation;
|
||||
export default TabBar;
|
|
@ -15,6 +15,7 @@ const TopNavigation = ( {
|
|||
onTitleClick = null,
|
||||
showProgressBar = false,
|
||||
progressBarPercent = 0,
|
||||
subNavigation = null,
|
||||
} ) => {
|
||||
const { goToWooCommercePaymentsTab } = useNavigation();
|
||||
const { isScrolled } = useIsScrolled();
|
||||
|
@ -40,7 +41,8 @@ const TopNavigation = ( {
|
|||
}, [] );
|
||||
|
||||
return (
|
||||
<div className={ className }>
|
||||
<>
|
||||
<nav className={ className }>
|
||||
<div className="ppcp-r-navigation">
|
||||
<BusyStateWrapper
|
||||
className="ppcp-r-navigation--left"
|
||||
|
@ -63,12 +65,19 @@ const TopNavigation = ( {
|
|||
>
|
||||
{ children }
|
||||
</BusyStateWrapper>
|
||||
</div>
|
||||
|
||||
{ subNavigation && (
|
||||
<section className="ppcp--top-sub-navigation">
|
||||
{ subNavigation }
|
||||
</section>
|
||||
) }
|
||||
|
||||
{ showProgressBar && (
|
||||
<ProgressBar percent={ progressBarPercent } />
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,272 +0,0 @@
|
|||
import { __, sprintf } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox, {
|
||||
BADGE_BOX_TITLE_BIG,
|
||||
} from '../../../ReusableComponents/BadgeBox';
|
||||
import { Separator } from '../../../ReusableComponents/Elements';
|
||||
import PricingTitleBadge from '../../../ReusableComponents/PricingTitleBadge';
|
||||
import OptionalPaymentMethods from './OptionalPaymentMethods';
|
||||
|
||||
const AcdcFlow = ( { isFastlane, isPayLater, storeCountry } ) => {
|
||||
if ( isFastlane && isPayLater && storeCountry === 'US' ) {
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__wrapper">
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
textBadge={ <PricingTitleBadge item="checkout" /> }
|
||||
description={ __(
|
||||
'Our all-in-one checkout solution lets you offer PayPal, Venmo, Pay Later options, and more to help maximise conversion',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Included in PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Pay with PayPal',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [ 'icon-button-paypal.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Our brand recognition helps give customers the confidence to buy. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Pay Later',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-payment-method-paypal-small.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="plater" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Offer installment payment options and get paid upfront. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __( 'Venmo', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-button-venmo.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Automatically offer Venmo checkout to millions of active users. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __( 'Crypto', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-crypto.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Let customers checkout with Crypto while you get paid in cash. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Expanded Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
description={ __(
|
||||
'Accept debit/credit cards, PayPal, Apple Pay, Google Pay, and more. Note: Additional application required for more methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<OptionalPaymentMethods
|
||||
useAcdc={ true }
|
||||
isFastlane={ isFastlane }
|
||||
isPayLater={ isPayLater }
|
||||
storeCountry={ storeCountry }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if ( isPayLater && storeCountry === 'UK' ) {
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__wrapper">
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
textBadge={ <PricingTitleBadge item="checkout" /> }
|
||||
description={ __(
|
||||
'Our all-in-one checkout solution lets you offer PayPal, Venmo, Pay Later options, and more to help maximise conversion',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Included in PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Pay with PayPal',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [ 'icon-button-paypal.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Our brand recognition helps give customers the confidence to buy. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Pay in 3',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-payment-method-paypal-small.svg',
|
||||
] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Offer installment payment options and get paid upfront - at no extra cost to you. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Optional payment methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
description={ __(
|
||||
'with additional application',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<OptionalPaymentMethods
|
||||
useAcdc={ true }
|
||||
isFastlane={ isFastlane }
|
||||
isPayLater={ isPayLater }
|
||||
storeCountry={ storeCountry }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__wrapper">
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
textBadge={ <PricingTitleBadge item="checkout" /> }
|
||||
description={ __(
|
||||
'Our all-in-one checkout solution lets you offer PayPal, Venmo, Pay Later options, and more to help maximise conversion',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Included in PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Pay with PayPal',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [ 'icon-button-paypal.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Our brand recognition helps give customers the confidence to buy. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __( 'Pay Later', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-paypal-small.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Offer installment payment options and get paid upfront. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Optional payment methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
description={ __(
|
||||
'with additional application',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<OptionalPaymentMethods
|
||||
useAcdc={ true }
|
||||
isFastlane={ isFastlane }
|
||||
isPayLater={ isPayLater }
|
||||
storeCountry={ storeCountry }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AcdcFlow;
|
|
@ -1,233 +0,0 @@
|
|||
import { __, sprintf } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox from '../../../ReusableComponents/BadgeBox';
|
||||
import { Separator } from '../../../ReusableComponents/Elements';
|
||||
import PricingTitleBadge from '../../../ReusableComponents/PricingTitleBadge';
|
||||
|
||||
const AcdcOptionalPaymentMethods = ( {
|
||||
isFastlane,
|
||||
isPayLater,
|
||||
storeCountry,
|
||||
} ) => {
|
||||
if ( isFastlane && isPayLater && storeCountry === 'US' ) {
|
||||
return (
|
||||
<div className="ppcp-r-optional-payment-methods__wrapper">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Custom Card Fields',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-visa.svg',
|
||||
'icon-button-mastercard.svg',
|
||||
'icon-button-amex.svg',
|
||||
'icon-button-discover.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="ccf" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Style the credit card fields to match your own style. Includes advanced processing with risk management, 3D Secure, fraud protection options, and chargeback protection. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-optional-payment-methods__separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Digital Wallets',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-apple-pay.svg',
|
||||
'icon-button-google-pay.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="dw" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Accept Apple Pay on eligible devices and Google Pay through mobile and web. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-optional-payment-methods__separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Alternative Payment Methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-ideal.svg',
|
||||
'icon-button-blik.svg',
|
||||
'icon-button-bancontact.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="apm" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Seamless payments for customers across the globe using their preferred payment methods. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-optional-payment-methods__separator" />
|
||||
<BadgeBox
|
||||
title={ __( '', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-fastlane-small.svg' ] }
|
||||
textBadge={
|
||||
<PricingTitleBadge item="fast country currency=storeCurrency=storeCountrylane" />
|
||||
}
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Speed up guest checkout with Fatslane. Link a customer\'s email address to their payment details. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if ( isPayLater && storeCountry === 'uk' ) {
|
||||
return (
|
||||
<div className="ppcp-r-optional-payment-methods__wrapper">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Custom Card Fields',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-visa.svg',
|
||||
'icon-button-mastercard.svg',
|
||||
'icon-button-amex.svg',
|
||||
'icon-button-discover.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="ccf" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Style the credit card fields to match your own style. Includes advanced processing with risk management, 3D Secure, fraud protection options, and chargeback protection. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-optional-payment-methods__separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Digital Wallets',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-apple-pay.svg',
|
||||
'icon-button-google-pay.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="dw" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Accept Apple Pay on eligible devices and Google Pay through mobile and web. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-optional-payment-methods__separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Alternative Payment Methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-sepa.svg',
|
||||
'icon-button-ideal.svg',
|
||||
'icon-button-blik.svg',
|
||||
'icon-button-bancontact.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="apm" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Seamless payments for customers across the globe using their preferred payment methods. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-optional-payment-methods__wrapper">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Custom Card Fields',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-visa.svg',
|
||||
'icon-button-mastercard.svg',
|
||||
'icon-button-amex.svg',
|
||||
'icon-button-discover.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="ccf" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Style the credit card fields to match your own style. Includes advanced processing with risk management, 3D Secure, fraud protection options, and chargeback protection. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-optional-payment-methods__separator" />
|
||||
<BadgeBox
|
||||
title={ __( 'Digital Wallets', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [
|
||||
'icon-button-apple-pay.svg',
|
||||
'icon-button-google-pay.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="dw" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Accept Apple Pay on eligible devices and Google Pay through mobile and web. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-optional-payment-methods__separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Alternative Payment Methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-sepa.svg',
|
||||
'icon-button-ideal.svg',
|
||||
'icon-button-blik.svg',
|
||||
'icon-button-bancontact.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="apm" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal business fees guide
|
||||
__(
|
||||
'Seamless payments for customers across the globe using their preferred payment methods. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://www.paypal.com/us/business/paypal-business-fees'
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AcdcOptionalPaymentMethods;
|
|
@ -1,182 +0,0 @@
|
|||
import { __, sprintf } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox, {
|
||||
BADGE_BOX_TITLE_BIG,
|
||||
} from '../../../ReusableComponents/BadgeBox';
|
||||
import { Separator } from '../../../ReusableComponents/Elements';
|
||||
import PricingTitleBadge from '../../../ReusableComponents/PricingTitleBadge';
|
||||
import OptionalPaymentMethods from './OptionalPaymentMethods';
|
||||
|
||||
const BcdcFlow = ( { isPayLater, storeCountry } ) => {
|
||||
if ( isPayLater && storeCountry === 'US' ) {
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__wrapper">
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
textBadge={ <PricingTitleBadge item="checkout" /> }
|
||||
description={ __(
|
||||
'Our all-in-one checkout solution lets you offer PayPal, Venmo, Pay Later options, and more to help maximise conversion',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Included in PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Pay with PayPal',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [ 'icon-button-paypal.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Our brand recognition helps give customers the confidence to buy. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Pay Later',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-payment-method-paypal-small.svg',
|
||||
] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Offer installment payment options and get paid upfront. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __( 'Venmo', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-button-venmo.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Automatically offer Venmo checkout to millions of active users. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __( 'Crypto', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-crypto.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Let customers checkout with Crypto while you get paid in cash. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Expanded Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
description={ __(
|
||||
'Accept debit/credit cards, PayPal, Apple Pay, Google Pay, and more. Note: Additional application required for more methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<OptionalPaymentMethods
|
||||
useAcdc={ false }
|
||||
isFastlane={ false }
|
||||
isPayLater={ isPayLater }
|
||||
storeCountry={ storeCountry }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__wrapper ppcp-r-welcome-docs__wrapper--one-col">
|
||||
<BadgeBox
|
||||
title={ __( 'PayPal Checkout', 'woocommerce-paypal-payments' ) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
textBadge={ <PricingTitleBadge item="checkout" /> }
|
||||
description={ __(
|
||||
'Our all-in-one checkout solution lets you offer PayPal, Venmo, Pay Later options, and more to help maximise conversion',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Included in PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
/>
|
||||
<BadgeBox
|
||||
title={ __( 'Pay with PayPal', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-button-paypal.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Our brand recognition helps give customers the confidence to buy. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __( 'Pay Later', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-paypal-small.svg' ] }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Offer installment payment options and get paid upfront. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Optional payment methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
titleType={ BADGE_BOX_TITLE_BIG }
|
||||
description={ __(
|
||||
'with additional application',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<OptionalPaymentMethods
|
||||
useAcdc={ false }
|
||||
isFastlane={ false }
|
||||
isPayLater={ isPayLater }
|
||||
storeCountry={ storeCountry }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BcdcFlow;
|
|
@ -1,64 +0,0 @@
|
|||
import { __, sprintf } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox from '../../../ReusableComponents/BadgeBox';
|
||||
import PricingTitleBadge from '../../../ReusableComponents/PricingTitleBadge';
|
||||
|
||||
const BcdcOptionalPaymentMethods = ( { isPayLater, storeCountry } ) => {
|
||||
if ( isPayLater && storeCountry === 'us' ) {
|
||||
return (
|
||||
<div className="ppcp-r-optional-payment-methods__wrapper">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Credit and Debit Cards',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-visa.svg',
|
||||
'icon-button-mastercard.svg',
|
||||
'icon-button-amex.svg',
|
||||
'icon-button-discover.svg',
|
||||
] }
|
||||
textBadge={
|
||||
<PricingTitleBadge item="standardCardFields" />
|
||||
}
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Process major credit and debit cards through PayPal’s card fields. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-optional-payment-methods__wrapper">
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Credit and Debit Cards',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-visa.svg',
|
||||
'icon-button-mastercard.svg',
|
||||
'icon-button-amex.svg',
|
||||
'icon-button-discover.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="standardCardFields" /> }
|
||||
description={ sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'Process major credit and debit cards through PayPal’s card fields. <a target="_blank" href="%s">Learn more</a>',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'https://woocommerce.com/document/woocommerce-paypal-payments/#manual-credential-input '
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BcdcOptionalPaymentMethods;
|
|
@ -1,7 +1,7 @@
|
|||
import { Button } from '@wordpress/components';
|
||||
import { useEffect } from '@wordpress/element';
|
||||
import classNames from 'classnames';
|
||||
import { openSignup } from '../../../ReusableComponents/Icons';
|
||||
import { OpenSignup } from '../../../ReusableComponents/Icons';
|
||||
import { useHandleOnboardingButton } from '../../../../hooks/useHandleConnections';
|
||||
import BusyStateWrapper from '../../../ReusableComponents/BusyStateWrapper';
|
||||
|
||||
|
@ -27,7 +27,7 @@ const ButtonOrPlaceholder = ( {
|
|||
const buttonProps = {
|
||||
className,
|
||||
variant,
|
||||
icon: showIcon ? openSignup : null,
|
||||
icon: showIcon ? OpenSignup : null,
|
||||
};
|
||||
|
||||
if ( href ) {
|
||||
|
|
|
@ -151,6 +151,7 @@ const ManualConnectionForm = () => {
|
|||
setToggled={ setManualConnectionMode }
|
||||
>
|
||||
<DataStoreControl
|
||||
__nextHasNoMarginBottom
|
||||
control={ TextControl }
|
||||
ref={ refClientId }
|
||||
label={ clientIdLabel }
|
||||
|
@ -166,6 +167,7 @@ const ManualConnectionForm = () => {
|
|||
</p>
|
||||
) }
|
||||
<DataStoreControl
|
||||
__nextHasNoMarginBottom
|
||||
control={ TextControl }
|
||||
ref={ refClientSecret }
|
||||
label={ secretKeyLabel }
|
||||
|
|
|
@ -21,9 +21,37 @@ const OnboardingNavigation = ( { stepDetails, onNext, onPrev } ) => {
|
|||
showProgressBar={ true }
|
||||
progressBarPercent={ percentage * 0.9 }
|
||||
>
|
||||
<Button variant="link" onClick={ goToWooCommercePaymentsTab }>
|
||||
<OnboardingNavigationActions
|
||||
onExit={ goToWooCommercePaymentsTab }
|
||||
isFirst={ isFirst }
|
||||
isDisabled={ isDisabled }
|
||||
showNext={ showNext }
|
||||
onNext={ onNext }
|
||||
/>
|
||||
</TopNavigation>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingNavigation;
|
||||
|
||||
const OnboardingNavigationActions = ( {
|
||||
isFirst,
|
||||
showNext,
|
||||
isDisabled,
|
||||
onExit,
|
||||
onNext,
|
||||
} ) => {
|
||||
// On first page we don't have any actions.
|
||||
if ( isFirst ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant="link" onClick={ onExit }>
|
||||
{ __( 'Save and exit', 'woocommerce-paypal-payments' ) }
|
||||
</Button>
|
||||
|
||||
{ showNext && (
|
||||
<Button
|
||||
variant="primary"
|
||||
|
@ -33,8 +61,6 @@ const OnboardingNavigation = ( { stepDetails, onNext, onPrev } ) => {
|
|||
{ __( 'Continue', 'woocommerce-paypal-payments' ) }
|
||||
</Button>
|
||||
) }
|
||||
</TopNavigation>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingNavigation;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { Icon } from '@wordpress/components';
|
||||
|
||||
import { logoPayPal } from '../../../ReusableComponents/Icons';
|
||||
import { LogoPayPal } from '../../../ReusableComponents/Icons';
|
||||
|
||||
const OnboardingHeader = ( props ) => {
|
||||
return (
|
||||
<section className="ppcp-r-onboarding-header">
|
||||
<div className="ppcp-r-onboarding-header__logo">
|
||||
<div className="ppcp-r-onboarding-header__logo-wrapper">
|
||||
<Icon icon={ logoPayPal } width="auto" height={ 38 } />
|
||||
<Icon icon={ LogoPayPal } width={ 110 } height={ 38 } />
|
||||
</div>
|
||||
</div>
|
||||
<div className="ppcp-r-onboarding-header__content">
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import AcdcOptionalPaymentMethods from './AcdcOptionalPaymentMethods';
|
||||
import BcdcOptionalPaymentMethods from './BcdcOptionalPaymentMethods';
|
||||
|
||||
const OptionalPaymentMethods = ( {
|
||||
useAcdc,
|
||||
isFastlane,
|
||||
isPayLater,
|
||||
storeCountry,
|
||||
} ) => {
|
||||
return (
|
||||
<div className="ppcp-r-optional-payment-methods">
|
||||
{ useAcdc ? (
|
||||
<AcdcOptionalPaymentMethods
|
||||
isFastlane={ isFastlane }
|
||||
isPayLater={ isPayLater }
|
||||
storeCountry={ storeCountry }
|
||||
/>
|
||||
) : (
|
||||
<BcdcOptionalPaymentMethods
|
||||
isPayLater={ isPayLater }
|
||||
storeCountry={ storeCountry }
|
||||
/>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OptionalPaymentMethods;
|
|
@ -0,0 +1,94 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox from '../../../ReusableComponents/BadgeBox';
|
||||
import PaymentMethodsGroup from './PaymentMethodsGroup';
|
||||
import { PayPalCheckout } from './PaymentOptions';
|
||||
import { usePaymentConfig } from '../hooks/usePaymentConfig';
|
||||
|
||||
const PaymentFlow = ( {
|
||||
useAcdc,
|
||||
isFastlane,
|
||||
isPayLater,
|
||||
storeCountry,
|
||||
onlyOptional = false,
|
||||
} ) => {
|
||||
const {
|
||||
includedMethods,
|
||||
optionalMethods,
|
||||
optionalTitle,
|
||||
optionalDescription,
|
||||
learnMoreConfig,
|
||||
} = usePaymentConfig( storeCountry, isPayLater, useAcdc, isFastlane );
|
||||
|
||||
if ( onlyOptional ) {
|
||||
return (
|
||||
<OptionalMethodsSection
|
||||
methods={ optionalMethods }
|
||||
learnMoreConfig={ learnMoreConfig }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__wrapper">
|
||||
<DefaultMethodsSection
|
||||
methods={ includedMethods }
|
||||
learnMoreConfig={ learnMoreConfig }
|
||||
/>
|
||||
|
||||
<OptionalMethodsSection
|
||||
title={ optionalTitle }
|
||||
description={ optionalDescription }
|
||||
methods={ optionalMethods }
|
||||
learnMoreConfig={ learnMoreConfig }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PaymentFlow;
|
||||
|
||||
const DefaultMethodsSection = ( { methods, learnMoreConfig } ) => {
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
<PayPalCheckout learnMore={ learnMoreConfig.PayPalCheckout } />
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Included in PayPal Checkout',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<PaymentMethodsGroup
|
||||
methods={ methods }
|
||||
learnMoreConfig={ learnMoreConfig }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const OptionalMethodsSection = ( {
|
||||
title = '',
|
||||
description = '',
|
||||
methods,
|
||||
learnMoreConfig,
|
||||
} ) => {
|
||||
if ( ! methods.length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__col">
|
||||
{ title && (
|
||||
<BadgeBox
|
||||
title={ title }
|
||||
description={ description }
|
||||
learnMoreLink={ learnMoreConfig.OptionalMethods }
|
||||
/>
|
||||
) }
|
||||
<PaymentMethodsGroup
|
||||
methods={ methods }
|
||||
learnMoreConfig={ learnMoreConfig }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
import { Separator } from '../../../ReusableComponents/Elements';
|
||||
|
||||
const PaymentMethodsGroup = ( { methods, learnMoreConfig } ) => {
|
||||
return (
|
||||
<>
|
||||
{ methods.map( ( method, index ) => (
|
||||
<PaymentMethodItem
|
||||
key={ method.name }
|
||||
{ ...method }
|
||||
learnMore={ learnMoreConfig[ method.name ] }
|
||||
showSeparator={ index < methods.length - 1 }
|
||||
/>
|
||||
) ) }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PaymentMethodsGroup;
|
||||
|
||||
const PaymentMethodItem = ( { Component, learnMore, showSeparator } ) => {
|
||||
return (
|
||||
<>
|
||||
<Component learnMore={ learnMore } />
|
||||
{ showSeparator && (
|
||||
<Separator className="ppcp-r-payment-method--separator" />
|
||||
) }
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import PricingTitleBadge from '../../../../ReusableComponents/PricingTitleBadge';
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const AlternativePaymentMethods = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Alternative Payment Methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
// 'icon-button-sepa.svg', // Enable this when the SEPA-Gateway is ready.
|
||||
'icon-button-ideal.svg',
|
||||
'icon-button-blik.svg',
|
||||
'icon-button-bancontact.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="apm" /> }
|
||||
description={ __(
|
||||
'Seamless payments for customers across the globe using their preferred payment methods.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AlternativePaymentMethods;
|
|
@ -0,0 +1,26 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import PricingTitleBadge from '../../../../ReusableComponents/PricingTitleBadge';
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const CardFields = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __( 'Custom Card Fields', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [
|
||||
'icon-button-visa.svg',
|
||||
'icon-button-mastercard.svg',
|
||||
'icon-button-amex.svg',
|
||||
'icon-button-discover.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="ccf" /> }
|
||||
description={ __(
|
||||
'Style the credit card fields to match your own style. Includes advanced processing with risk management, 3D Secure, fraud protection options, and chargeback protection.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardFields;
|
|
@ -0,0 +1,29 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import PricingTitleBadge from '../../../../ReusableComponents/PricingTitleBadge';
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const CreditDebitCards = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Credit and Debit Cards',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
'icon-button-visa.svg',
|
||||
'icon-button-mastercard.svg',
|
||||
'icon-button-amex.svg',
|
||||
'icon-button-discover.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="standardCardFields" /> }
|
||||
description={ __(
|
||||
'Process major credit and debit cards through PayPal’s card fields.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreditDebitCards;
|
|
@ -0,0 +1,19 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const Crypto = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __( 'Crypto', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-crypto.svg' ] }
|
||||
description={ __(
|
||||
'Let customers checkout with Crypto while you get paid in cash.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Crypto;
|
|
@ -0,0 +1,23 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import PricingTitleBadge from '../../../../ReusableComponents/PricingTitleBadge';
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const DigitalWallets = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __( 'Digital Wallets', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [
|
||||
'icon-button-apple-pay.svg',
|
||||
'icon-button-google-pay.svg',
|
||||
] }
|
||||
textBadge={ <PricingTitleBadge item="dw" /> }
|
||||
description={ __(
|
||||
'Accept Apple Pay on eligible devices and Google Pay through mobile and web.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DigitalWallets;
|
|
@ -0,0 +1,22 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import PricingTitleBadge from '../../../../ReusableComponents/PricingTitleBadge';
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const Fastlane = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __( '', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-fastlane-small.svg' ] }
|
||||
textBadge={
|
||||
<PricingTitleBadge item="fast country currency=storeCurrency=storeCountrylane" />
|
||||
}
|
||||
description={ __(
|
||||
"Speed up guest checkout with Fatslane. Link a customer's email address to their payment details.",
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Fastlane;
|
|
@ -0,0 +1,19 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const PayInThree = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __( 'Pay in 3', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-paypal-small.svg' ] }
|
||||
description={ __(
|
||||
'Offer installment payment options and get paid upfront - at no extra cost to you.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PayInThree;
|
|
@ -0,0 +1,19 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const PayLater = ( { learnMore = '' } ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __( 'Pay Later', 'woocommerce-paypal-payments' ) }
|
||||
imageBadge={ [ 'icon-payment-method-paypal-small.svg' ] }
|
||||
description={ __(
|
||||
'Offer installment payment options and get paid upfront.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PayLater;
|
|
@ -0,0 +1,22 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import PricingTitleBadge from '../../../../ReusableComponents/PricingTitleBadge';
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const PayPalCheckout = ( {
|
||||
learnMore = 'https://www.paypal.com/us/business/accept-payments/checkout',
|
||||
} ) => {
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __( 'PayPal Checkout', 'woocommerce-paypal-payments' ) }
|
||||
textBadge={ <PricingTitleBadge item="checkout" /> }
|
||||
description={ __(
|
||||
'Our all-in-one checkout solution lets you offer PayPal, Venmo, Pay Later options, and more to help maximise conversion',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
learnMoreLink={ learnMore }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PayPalCheckout;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue