From 2a40016c69a4196af81ce87b903026c07ca069f4 Mon Sep 17 00:00:00 2001 From: Joshua Dinh <75056371+JoshuaHungDinh@users.noreply.github.com> Date: Thu, 2 Nov 2023 08:33:14 -0700 Subject: [PATCH] Feature: update Giving Tuesday banner (#7073) --- assets/src/css/admin/sale-banners.scss | 223 +++++++++--------- assets/src/css/admin/settings.scss | 3 +- .../bfcm-banner/background-image-lg.svg | 9 + .../bfcm-banner/background-image-md.svg | 11 + .../bfcm-banner/background-image-s.svg | 11 + .../promotions/bfcm-banner/dismiss-icon.svg | 5 + .../bfcm-banner/shopping-cart-icon.svg | 11 + .../InPluginUpsells/SaleBanners.php | 131 ++++++++-- .../InPluginUpsells/SummerSalesBanner.php | 156 ------------ .../resources/js/sale-banner.js | 20 +- .../resources/views/sale-banners.php | 83 ++++--- .../resources/views/summer-sales-banner.php | 76 ------ src/Promotions/ServiceProvider.php | 5 - 13 files changed, 344 insertions(+), 400 deletions(-) create mode 100644 assets/src/images/admin/promotions/bfcm-banner/background-image-lg.svg create mode 100644 assets/src/images/admin/promotions/bfcm-banner/background-image-md.svg create mode 100644 assets/src/images/admin/promotions/bfcm-banner/background-image-s.svg create mode 100644 assets/src/images/admin/promotions/bfcm-banner/dismiss-icon.svg create mode 100644 assets/src/images/admin/promotions/bfcm-banner/shopping-cart-icon.svg delete mode 100644 src/Promotions/InPluginUpsells/SummerSalesBanner.php delete mode 100644 src/Promotions/InPluginUpsells/resources/views/summer-sales-banner.php diff --git a/assets/src/css/admin/sale-banners.scss b/assets/src/css/admin/sale-banners.scss index 7e580e7e75..589d3c1e6e 100644 --- a/assets/src/css/admin/sale-banners.scss +++ b/assets/src/css/admin/sale-banners.scss @@ -1,4 +1,14 @@ -.give-sale-banners-container { +.givewp-sale-banners-container { + display: block; + width: 100%; + position: relative; + padding: 1.75rem 0 1.5rem 2.75rem; + box-shadow: 0 0.0625em 0.25em rgba(0, 0, 0, 0.25); + background-repeat: no-repeat; + background-size: cover; + background-position: center center; + border-radius: 8px; + /* Box-sizing reset */ &, & *, @@ -7,146 +17,141 @@ box-sizing: border-box; } - display: grid; - row-gap: 1.875rem; font-family: 'Open Sans', system-ui, sans-serif; #give-in-plugin-upsells & { margin-top: 2rem; margin-bottom: 0.5rem; } +} - .give_forms_page_give-payment-history &, - .give_forms_page_give-donors &, - .post-type-give_forms.post-new-php &, - .post-type-give_forms.edit-php & { - background-color: #fff; - margin: -10px -20px 30px -20px; - border-bottom: 1px solid #dbdbdb; - padding: 30px 20px; +/* List Table pages */ +#give-admin-donations-root, #give-admin-donation-forms-root, #give-admin-donors-root { + .givewp-sale-banners-container { + width: auto; + margin: 1rem; } - } -.give-sale-banner { - --sale-icon-size: 2.5em; - --bg-gradient: linear-gradient(85.79deg, #1da3b0 44.27%, #9fd894 100%); - - display: grid; - align-items: stretch; - align-content: center; - grid-template-columns: min-content auto min-content; - column-gap: 1em; - --banner-y-pad: 0.6875em; - padding-top: var(--banner-y-pad); - padding-bottom: var(--banner-y-pad); - padding-left: 1.0625em; - padding-right: 1.3125em; - background-image: var(--bg-gradient); - box-shadow: 0 0.0625em 0.25em rgba(0, 0, 0, 0.25); - color: #fff; - font-size: clamp(max(0.875rem, 14px), 2vw, max(1rem, 16px)); +/* Add Form page */ +.post-type-give_forms { + .givewp-sale-banners-container { + width: 100%; + margin: 1.55rem 0 0 0; + } } -.give-sale-banner-icon { - width: var(--sale-icon-size); - height: var(--sale-icon-size); +/* Settings & Tools page */ +.give_forms_page_give-settings, .give-tools-setting-page{ + .givewp-sale-banners-container { + width: 100%; + margin: .5rem 0; + } } -.give-sale-banner-content { - display: grid; - align-items: center; - row-gap: 0.5em; - - & * { - font-size: inherit; +/* Reports page */ +.give_forms_page_give-reports { + .givewp-sale-banners-container { + margin: .5rem 0 0 0; } +} - & a { - display: inline-block; - color: inherit; - font-weight: 700; - text-decoration-thickness: 0.05em; - transform-style: preserve-3d; - - &::after { - content: ""; - position: absolute; - transform: translateZ(-1px); - display: block; - background-color: #fff; - height: calc(100% + 0.2em); - width: calc(100% + 0.6em); - top: -0.1em; - left: -0.3em; - opacity: 0; - box-shadow: 0 0.0625em 0.125em rgba(0, 0, 0, 0.05); - transition: opacity 0.2s ease-in-out; +.givewp-sale-banner { + &__content { + width: 70%; + line-height: normal; + font-style: normal; + + & h2 { + font-size: 2rem; + font-weight: 700; + margin: 0; + color: #022603; + line-height: 1; + + & strong { + color: #459948; + font-weight: 900; + } } - &:focus { - outline: none; - box-shadow: none; + & p { + font-size: 1.25rem !important; + font-weight: 500; } - &:hover, - &:focus { - background-image: var(--bg-gradient); - background-clip: text; - color: transparent; + & a { + display: inline-flex; + padding: 1rem 1.5rem; + justify-content: center; + align-items: center; + gap: .5rem; + background: #459948; + border-radius: 36px; + border: none; + color: var(--shades-white, #FFF); + font-size: 1.25rem; + font-weight: 600; + cursor: pointer; text-decoration: none; - &::after { - opacity: 1; + &:hover { + background: #2D802F; } } } - & p { - display: flex; - flex-wrap: wrap; - row-gap: 0.25rem; - column-gap: 0.9375em; - margin: 0; - line-height: 1.37; + &__dismiss { + position: absolute; + top: .5rem; + right: .5rem; + background: none; + border: none; + cursor: pointer; } } -.give-sale-banner-dismiss { - --size: 1.25rem; - /* Artificially align this with the sale icon, since we shouldn’t use align-items: center on the banner */ - margin-top: calc((var(--sale-icon-size) - var(--size)) / 2); - appearance: none; - background: none; - display: grid; - place-content: center; - padding: 0; - width: var(--size); - height: var(--size); - border: 0; - border-radius: 9999px; - outline-offset: 0.25rem; - color: inherit; - cursor: pointer; - font-size: inherit; - transition: color 0.2s, transform 0.2s; - - & svg { - width: var(--size); - height: var(--size); - transition: fill 200ms ease-in-out; - - fill: none; - - /* This ensures that the event target is the button when clicked. */ - pointer-events: none; +/* Media query for small screens */ +@media screen and (max-width: 768px) { + .givewp-sale-banners-container { + padding: 1.25rem 0 1.5rem 1.5rem; } - &:hover { - transform: scale(1.15); + .givewp-sale-banner__content { + & h2 { + font-size: 1.125rem; + } + + & p { + margin: .5rem 0 1rem 0; + font-size: 0.875rem !important; + line-height: 1.75rem; + + } + + & a { + font-size: 0.875rem; + padding: .75rem 1rem; + } } +} + - &:active { - transform: scale(0.95); +/* Media query for medium screens */ +@media screen and (min-width: 769px) and (max-width: 1024px) { + .givewp-sale-banner__content { + & h2 { + font-size: 1.75rem; + } + + & p { + font-size: 1.125rem !important; + line-height: 1.5rem; + margin: .75rem 0 1rem 0; + } + + & a { + font-size: 1rem; + } } } diff --git a/assets/src/css/admin/settings.scss b/assets/src/css/admin/settings.scss index 0e8271b6c3..4fbc1483c6 100644 --- a/assets/src/css/admin/settings.scss +++ b/assets/src/css/admin/settings.scss @@ -105,7 +105,8 @@ // White bg header. .give-settings-header { display: flex; - align-items: center; + flex-direction: column; + align-items: flex-start; justify-content: space-between; background: #fff; padding: 10px 20px; diff --git a/assets/src/images/admin/promotions/bfcm-banner/background-image-lg.svg b/assets/src/images/admin/promotions/bfcm-banner/background-image-lg.svg new file mode 100644 index 0000000000..1a4bf2b7e2 --- /dev/null +++ b/assets/src/images/admin/promotions/bfcm-banner/background-image-lg.svg @@ -0,0 +1,9 @@ + diff --git a/assets/src/images/admin/promotions/bfcm-banner/background-image-md.svg b/assets/src/images/admin/promotions/bfcm-banner/background-image-md.svg new file mode 100644 index 0000000000..e239a8f93d --- /dev/null +++ b/assets/src/images/admin/promotions/bfcm-banner/background-image-md.svg @@ -0,0 +1,11 @@ + diff --git a/assets/src/images/admin/promotions/bfcm-banner/background-image-s.svg b/assets/src/images/admin/promotions/bfcm-banner/background-image-s.svg new file mode 100644 index 0000000000..012d9004b9 --- /dev/null +++ b/assets/src/images/admin/promotions/bfcm-banner/background-image-s.svg @@ -0,0 +1,11 @@ + diff --git a/assets/src/images/admin/promotions/bfcm-banner/dismiss-icon.svg b/assets/src/images/admin/promotions/bfcm-banner/dismiss-icon.svg new file mode 100644 index 0000000000..e3b1c94371 --- /dev/null +++ b/assets/src/images/admin/promotions/bfcm-banner/dismiss-icon.svg @@ -0,0 +1,5 @@ + diff --git a/assets/src/images/admin/promotions/bfcm-banner/shopping-cart-icon.svg b/assets/src/images/admin/promotions/bfcm-banner/shopping-cart-icon.svg new file mode 100644 index 0000000000..b005a3f9d4 --- /dev/null +++ b/assets/src/images/admin/promotions/bfcm-banner/shopping-cart-icon.svg @@ -0,0 +1,11 @@ + diff --git a/src/Promotions/InPluginUpsells/SaleBanners.php b/src/Promotions/InPluginUpsells/SaleBanners.php index c4c879a5b8..a92ac0b92f 100644 --- a/src/Promotions/InPluginUpsells/SaleBanners.php +++ b/src/Promotions/InPluginUpsells/SaleBanners.php @@ -33,6 +33,7 @@ public function __construct() /** * Get banners definitions * + * @unreleased add Giving Tuesday 2023 banner * @since 2.23.2 add Giving Tuesday 2022 banner * @since 2.17.0 * @@ -42,26 +43,46 @@ public function getBanners(): array { return [ [ - 'id' => 'bfgt2021', - 'iconURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/sale-icon.png', + 'id' => 'bfgt2023', + 'giveIconURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/promotions/bfcm-banner/give-logo-icon.svg', + 'discountIconURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/promotions/bfcm-banner/discount-icon.svg', + 'backgroundImageLargeURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/promotions/bfcm-banner/background-image-lg.svg', + 'backgroundImageMediumURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/promotions/bfcm-banner/background-image-md.svg', + 'backgroundImageSmallURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/promotions/bfcm-banner/background-image-s.svg', + 'shoppingCartIconURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/promotions/bfcm-banner/shopping-cart-icon.svg', + 'dismissIconURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/promotions/bfcm-banner/dismiss-icon.svg', 'accessibleLabel' => __('Black Friday/Giving Tuesday Sale', 'give'), - 'leadText' => __('Save 40% on all Plans for a limited time.', 'give'), - 'contentText' => __('Black Friday through Giving Tuesday.', 'give'), + 'leadText' => self::getDataByPricingPlan( + [ + 'Free' => __( + 'Upgrade to a Pricing Plan for Recurring Donations, Fee Recovery, and more.', + 'give' + ), + 'Basic' => __( + 'Upgrade to a Plus Plan to get all must-have add-ons.', + 'give' + ), + 'Plus' => __( + 'Upgrade to Pro and get Peer-to-Peer fundraising.', + 'give' + ), + 'default' => __( + 'Upgrade to a Pricing Plan for Recurring Donations, Fee Recovery, and more.', + 'give' + ), + ] + ), 'actionText' => __('Shop Now', 'give'), - 'actionURL' => 'https://go.givewp.com/bfgt21', - 'startDate' => '2021-11-26 00:00', - 'endDate' => '2021-11-30 23:59', - ], - [ - 'id' => 'bfgt2022', - 'iconURL' => GIVE_PLUGIN_URL . 'assets/dist/images/admin/sale-icon.png', - 'accessibleLabel' => __('Black Friday/Giving Tuesday Sale', 'give'), - 'leadText' => __('Save 40% on all Plans for a limited time.', 'give'), - 'contentText' => __('Black Friday through Giving Tuesday.', 'give'), - 'actionText' => __('Shop Now', 'give'), - 'actionURL' => 'https://go.givewp.com/bf22', - 'startDate' => '2022-11-01 00:00', - 'endDate' => '2022-11-29 23:59', + 'actionURL' => self::getDataByPricingPlan( + [ + 'Free' => 'https://go.givewp.com/bf23', + 'Basic' => 'https://go.givewp.com/bfup23', + 'Plus' => 'https://go.givewp.com/bfup23', + 'Default' => 'https://go.givewp.com/bfup23', + ] + ), + 'startDate' => '2023-11-20 00:00', + 'endDate' => '2023-11-29 23:59', ], ]; } @@ -69,10 +90,15 @@ public function getBanners(): array /** * Get the banners that should be displayed. * + * @unreleased hide banners for users with Pro tier accounts. * @since 2.17.0 */ public function getVisibleBanners(): array { + if (self::getUserPricingPlan() === 'Pro') { + return []; + } + $currentDateTime = current_datetime(); $currentUserId = get_current_user_id(); $giveWPWebsiteTimezone = new DateTimeZone('America/Los_Angeles'); @@ -85,7 +111,7 @@ function ($banner) use ($currentDateTime, $currentUserId, $giveWPWebsiteTimezone try { $isFuture = $currentDateTime < new DateTimeImmutable($banner['startDate'], $giveWPWebsiteTimezone); $isPast = $currentDateTime > new DateTimeImmutable($banner['endDate'], $giveWPWebsiteTimezone); - } catch(Exception $exception) { + } catch (Exception $exception) { return false; } @@ -161,4 +187,71 @@ public static function isShowing(): bool { return isset($_GET['post_type']) && $_GET['post_type'] === 'give_forms'; } + + /** + * @unreleased retrieve licensed plugin slugs. + */ + public static function getLicensedPluginSlugs(): array + { + $pluginSlugs = []; + $licenses = get_option("give_licenses", []); + + foreach ($licenses as $license) { + if (isset($license['is_all_access_pass']) && $license['is_all_access_pass'] && !empty($license['download'])) { + $pluginSlugs = ['is_all_access_pass']; + } else { + $pluginSlugs[] = $license['plugin_slug']; + } + } + + return $pluginSlugs; + } + + /** + * @unreleased determines user pricing plan from licensed plugin slugs. + */ + public static function getUserPricingPlan(): string + { + $plan = 'Free'; + + $pricingPlans = [ + 'Basic' => ['pdf' => 'give-pdf-receipts'], + 'Plus' => [ + 'pdf_receipts' => 'give-pdf-receipts', + 'recurring_donations' => 'give-recurring', + 'fee_recovery' => 'give-fee-recovery', + 'form_field_manager' => 'give-form-field-manager', + 'tributes' => 'give-tributes', + 'annual_receipts' => 'give-annual-receipts', + 'peer_to_peer' => 'give-peer-to-peer', + ], + 'Pro' => ['is_all_access_pass'], + ]; + + $licensedPluginSlugs = self::getLicensedPluginSlugs(); + + foreach ($pricingPlans as $planName => $requiredLicenses) { + $missingLicenses = array_diff($requiredLicenses, $licensedPluginSlugs); + if (empty($missingLicenses)) { + $plan = $planName; + } + } + + return $plan; + } + + /** + * @unreleased return data by user pricing plan. + */ + public static function getDataByPricingPlan($data): string + { + $userPricingPlan = self::getUserPricingPlan(); + + if (array_key_exists($userPricingPlan, $data)) { + return $data[$userPricingPlan]; + } + + return $data['default']; + } } + diff --git a/src/Promotions/InPluginUpsells/SummerSalesBanner.php b/src/Promotions/InPluginUpsells/SummerSalesBanner.php deleted file mode 100644 index 407f12e866..0000000000 --- a/src/Promotions/InPluginUpsells/SummerSalesBanner.php +++ /dev/null @@ -1,156 +0,0 @@ - __('Save 30% on all GiveWP Pricing Plans.', 'give'), - 'leadHeader' => __('Make it yours.', 'give'), - 'contentText' => __( - 'Purchase any StellarWP product during the sale and get 100% off WP Business Reviews and take 40% off all other brands.', - 'give' - ), - 'actionText' => __('Shop Now', 'give'), - 'alternateActionText' => __('View all StellarWP Deals', 'give'), - 'alternateActionURL' => 'https://go.givewp.com/ss23stellar', - 'startDate' => '2023-07-24 00:00', - 'endDate' => '2023-07-31 23:59', - ]; - - $hasValidLicenses = self::hasValidLicenses(); - - if ($hasValidLicenses) { - return [ - array_merge($commonBannerInfo, [ - 'id' => 'bfgt2023stellar', - 'leadText' => __('Save 30% on all StellarWP products.', 'give'), - 'actionURL' => 'https://go.givewp.com/ss23stellar', - ]), - ]; - } - - return [ - array_merge($commonBannerInfo, [ - 'id' => 'bfgt2023givewp', - 'leadText' => __('Save 30% on all GiveWP Pricing Plans.', 'give'), - 'actionURL' => 'https://go.givewp.com/ss23give', - - ]), - ]; - } - - - /** - * @unrleased - */ - public function loadScripts() - { - wp_enqueue_script( - 'give-in-plugin-upsells-sale-banners', - GIVE_PLUGIN_URL . 'assets/dist/js/admin-upsell-sale-banner.js', - [], - GIVE_VERSION, - true - ); - - wp_localize_script( - 'give-in-plugin-upsells-sale-banners', - 'GiveSaleBanners', - [ - 'apiRoot' => esc_url_raw(rest_url('give-api/v2/sale-banner')), - 'apiNonce' => wp_create_nonce('wp_rest'), - ] - ); - - wp_enqueue_style( - 'give-in-plugin-upsells-summer-sales-banner', - GIVE_PLUGIN_URL . 'assets/dist/css/admin-summer-sales-banner.css', - [], - GIVE_VERSION - ); - - wp_enqueue_style('givewp-admin-fonts'); - - wp_enqueue_style( - 'Inconsolpata', - 'https://fonts.googleapis.com/css2?family=Inconsolata&display=swap', - [], - '1.0', - 'all' - ); - } - - /** - * @since 2.31.0 - */ - public function render() - { - $banner = $this->getVisibleBanners(); - - if ( ! empty($banner)) { - include __DIR__ . '/resources/views/summer-sales-banner.php'; - } - } - - - /** - * @since 2.31.0 - */ - public static function isShowing(): bool - { - global $pagenow; - - return $pagenow === 'plugins.php'; - } - - /** - * @since 2.31.0 - */ - public static function hasValidLicenses(): bool - { - $requiredPluginSlugs = [ - 'recurring' => 'give-recurring', - 'form_field_manager' => 'give-form-field-manager', - 'fee_recovery' => 'give-fee-recovery', - 'manual_donations' => 'give-manual-donations', - 'peer_to_peer' => 'give-peer-to-peer', - ]; - - $licensedPluginSlugs = self::getLicensedPluginSlugs(); - - sort($requiredPluginSlugs); - sort($licensedPluginSlugs); - - return $requiredPluginSlugs == $licensedPluginSlugs; - } - - /** - * @since 2.31.0 - */ - public static function getLicensedPluginSlugs(): array - { - $pluginSlugs = []; - $licenses = get_option("give_licenses", []); - - foreach ($licenses as $license) { - if (isset($license['is_all_access_pass']) && $license['is_all_access_pass'] && ! empty($license['download'])) { - $slugs = array_column($license['download'], 'plugin_slug'); - $pluginSlugs = array_merge($pluginSlugs, $slugs); - } else { - $pluginSlugs[] = $license['plugin_slug']; - } - } - - return $pluginSlugs; - } -} - diff --git a/src/Promotions/InPluginUpsells/resources/js/sale-banner.js b/src/Promotions/InPluginUpsells/resources/js/sale-banner.js index 32647177b8..7e61d34065 100644 --- a/src/Promotions/InPluginUpsells/resources/js/sale-banner.js +++ b/src/Promotions/InPluginUpsells/resources/js/sale-banner.js @@ -1,7 +1,11 @@ -const bannersContainer = document.querySelector('.give-sale-banners-container'); -const dismissActions = document.querySelectorAll('.give-sale-banner-dismiss'); +const bannersContainer = document.querySelector('.givewp-sale-banners-container'); +const dismissActions = document.querySelectorAll('.givewp-sale-banner__dismiss'); const pageTitle = document.querySelector('.page-title-action, .wp-heading-inline, #give-in-plugin-upsells h1'); +const listTable = document.querySelector('#give-admin-donations-root, #give-admin-donation-forms-root, #give-admin-donors-root'); +/** + * @unreleased show banner on ListTable pages. + */ const hideBanner = ({target: dismissAction}) => { const formData = new FormData(); formData.append('id', dismissAction.dataset.id); @@ -16,15 +20,19 @@ const hideBanner = ({target: dismissAction}) => { body: formData, }); - if (bannersContainer.querySelectorAll('.give-sale-banner').length === 0) { + if (bannersContainer.querySelectorAll('.givewp-sale-banner').length === 0) { bannersContainer.remove(); } }; -if (pageTitle && bannersContainer) { - pageTitle.parentNode.insertBefore(bannersContainer, pageTitle.nextSibling); - +if((pageTitle || listTable) && bannersContainer ){ bannersContainer.style.display = null; + + if (pageTitle) { + pageTitle.parentNode.insertBefore(bannersContainer, pageTitle.nextSibling); + } else if (listTable){ + listTable.querySelector('header').insertAdjacentElement('afterend', bannersContainer); + } } dismissActions.forEach((action) => { diff --git a/src/Promotions/InPluginUpsells/resources/views/sale-banners.php b/src/Promotions/InPluginUpsells/resources/views/sale-banners.php index db79a604cb..4a5a776cc7 100644 --- a/src/Promotions/InPluginUpsells/resources/views/sale-banners.php +++ b/src/Promotions/InPluginUpsells/resources/views/sale-banners.php @@ -1,48 +1,75 @@ - -