From 488d9bb13590e4eefbe60a5213a668928acb3309 Mon Sep 17 00:00:00 2001 From: Aileen Booker Date: Thu, 26 Jan 2023 14:42:11 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Added=20referrals=20invite=20notifi?= =?UTF-8?q?cation=20(#16187)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no issue - Ghost users that make >= $100 MRR will see a dismissible notification that invites them to the Ghost Referral program - Only applies to Admin and Owner users and when Stripe is setup and connected in live mode - By saving a `referralInviteDismissed` property to the users' `accessibility` JSON object we can determine if the notification has been dismissed and won't show it again - Added new `gh-referral-invite` component --- .../app/components/gh-nav-menu/footer.hbs | 8 +- .../app/components/gh-referral-invite.hbs | 10 +++ .../app/components/gh-referral-invite.js | 68 +++++++++++++++ ghost/admin/app/services/feature.js | 3 + ghost/admin/app/styles/app-dark.css | 6 +- ghost/admin/app/styles/layouts/main.css | 87 +++++++++++++++++-- 6 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 ghost/admin/app/components/gh-referral-invite.hbs create mode 100644 ghost/admin/app/components/gh-referral-invite.js diff --git a/ghost/admin/app/components/gh-nav-menu/footer.hbs b/ghost/admin/app/components/gh-nav-menu/footer.hbs index fc8f6e59a5..f00a24e5a7 100644 --- a/ghost/admin/app/components/gh-nav-menu/footer.hbs +++ b/ghost/admin/app/components/gh-nav-menu/footer.hbs @@ -1,11 +1,13 @@
{{#if this.hasThemeErrors}} - {{/if}} + +
diff --git a/ghost/admin/app/components/gh-referral-invite.hbs b/ghost/admin/app/components/gh-referral-invite.hbs new file mode 100644 index 0000000000..aac72684d6 --- /dev/null +++ b/ghost/admin/app/components/gh-referral-invite.hbs @@ -0,0 +1,10 @@ +{{#if this.showReferralInvite}} + +{{/if}} \ No newline at end of file diff --git a/ghost/admin/app/components/gh-referral-invite.js b/ghost/admin/app/components/gh-referral-invite.js new file mode 100644 index 0000000000..4125279f87 --- /dev/null +++ b/ghost/admin/app/components/gh-referral-invite.js @@ -0,0 +1,68 @@ +import Component from '@glimmer/component'; +import envConfig from 'ghost-admin/config/environment'; +import moment from 'moment-timezone'; +import {action} from '@ember/object'; +import {inject as service} from '@ember/service'; +import {task} from 'ember-concurrency'; + +export default class GhReferralInvite extends Component { + @service session; + @service dashboardStats; + @service feature; + @service membersUtils; + @service settings; + + constructor() { + super(...arguments); + this.loadCurrentMRR.perform(); + } + + get isAdminOrOwner() { + return this.session.user.isAdmin; + } + + get isReferralNotificationNotDismissed() { + return !this.feature.accessibility.referralInviteDismissed; + } + + get stripeLiveModeEnabled() { + // allow testing mode when not in a production environment + const isDevModeStripeEnabled = envConfig.environment !== 'production' && this.membersUtils.isStripeEnabled; + const isLiveEnabled = this.settings.stripeConnectLivemode; + return isDevModeStripeEnabled || isLiveEnabled; + } + + get hasReachedMRR() { + return this.dashboardStats.currentMRR / 100 >= 100; + } + + get showReferralInvite() { + // Conditions to see the referral invite + // 1. Needs to be Owner or Admin + // 2. Stripe is setup and enabled in live mode + // 3. MRR is > $100 + // 4. Notification has not yet been dismissed by the user + return !this.args.hasThemeErrors && this.isAdminOrOwner && this.isReferralNotificationNotDismissed && this.stripeLiveModeEnabled && this.hasReachedMRR; + } + + @task + *loadCurrentMRR() { + if (this.isAdminOrOwnern) { + try { + yield this.dashboardStats.loadMrrStats(); + } catch (error) { + // noop + } + } + } + + @action + dismissReferralInvite(event) { + event.preventDefault(); + event.stopPropagation(); + + if (!this.feature.referralInviteDismissed) { + this.feature.referralInviteDismissed = moment().tz(this.settings.timezone); + } + } +} diff --git a/ghost/admin/app/services/feature.js b/ghost/admin/app/services/feature.js index d630d6f045..b84bcf2159 100644 --- a/ghost/admin/app/services/feature.js +++ b/ghost/admin/app/services/feature.js @@ -55,6 +55,9 @@ export default class FeatureService extends Service { @feature('nightShift', {user: true, onChange: '_setAdminTheme'}) nightShift; + // user-specific referral invitation + @feature('referralInviteDismissed', {user: true}) referralInviteDismissed; + // labs flags @feature('urlCache') urlCache; @feature('beforeAfterCard') beforeAfterCard; diff --git a/ghost/admin/app/styles/app-dark.css b/ghost/admin/app/styles/app-dark.css index 6086ece49d..ae4fb0a45f 100644 --- a/ghost/admin/app/styles/app-dark.css +++ b/ghost/admin/app/styles/app-dark.css @@ -810,6 +810,10 @@ input:focus, background: color-mod(var(--dark-main-bg-color) l(+2%)); } +.gh-referral-toast-close:hover { + color: #fff; +} + .nightshift-toggle { background: var(--lightgrey); } @@ -1486,4 +1490,4 @@ kbd { .gh-mention-your-post-link { color: var(--black); -} \ No newline at end of file +} diff --git a/ghost/admin/app/styles/layouts/main.css b/ghost/admin/app/styles/layouts/main.css index 4c3de9b94b..c681af41bf 100644 --- a/ghost/admin/app/styles/layouts/main.css +++ b/ghost/admin/app/styles/layouts/main.css @@ -2149,8 +2149,8 @@ section.gh-ds h2 { } -/* Theme error toast and modal */ -.gh-theme-error-toast { +/* Footer toast in navbar */ +.gh-footer-toast { display: flex; flex-direction: column; font-size: 1.3rem; @@ -2159,10 +2159,87 @@ section.gh-ds h2 { padding: 20px; margin-bottom: 32px; color: #fff; - background: var(--red); border-radius: 6px; } -.gh-theme-error-toast .gh-notification-title { +.gh-footer-toast-title.gh-notification-title { margin: 0 0 6px 0; -} \ No newline at end of file +} + +/* Theme error toast and modal */ +.gh-theme-error-toast { + background: var(--red); +} + +/* Ghost Referrals invite toast */ +.gh-referral-toast { + position: relative; + display: block; + padding: 25px; + margin-bottom: 50px; + color: var(--black); + text-decoration: none; + background: var(--white); + border-radius: 10px; + box-shadow: rgb(75 225 226 / 28%) -7px -6px 42px 8px, rgb(202 103 255 / 32%) 7px 6px 42px 8px; + transition: all 0.6s ease; + cursor: pointer; +} + +.gh-referral-toast a { + color: var(--black); +} + +.gh-referral-toast:hover { + transform: translateY(-2px) scale(1.01); + box-shadow: rgb(75 225 226 / 38%) -7px -4px 42px 10px, rgb(202 103 255 / 42%) 7px 8px 42px 10px; + transition: all 0.3s ease; + } + +.gh-referral-toast-close { + position: absolute; + top: 7px; + right: 10px; + padding: 5px; + color: #ddd; + font-size: 2.2rem; + line-height: 1; +} + +.gh-referral-toast-close:hover { + color: #15171A; +} + +.gh-referral-toast a > strong { + display: block; + margin-bottom: 10px; + font-size: 1.7rem; + line-height: 1.2em; +} + +.gh-referral-toast a > p { + margin: 0; + font-size: 1.5rem; + line-height: 1.35em; + letter-spacing: -0.015em; + font-weight: 500; + color: #666; +} + +.gh-referral-toast a > p strong { + color: #ff247d; +} + +.gh-referral-toast-button { + margin-top: 20px; + border-radius: 5px; + width: 100%; +} + +.gh-referral-toast-button span { + padding: 0 12px; + font-size: 1.4rem; + text-align-last: center; + height: 40px; + line-height: 40px; +}