diff --git a/ghost/portal/src/components/Frame.styles.js b/ghost/portal/src/components/Frame.styles.js index a2194fdc29..5a331e4101 100644 --- a/ghost/portal/src/components/Frame.styles.js +++ b/ghost/portal/src/components/Frame.styles.js @@ -476,6 +476,10 @@ const FrameStyles = ` color: var(--grey6); } + .gh-portal-list-detail .old-price { + text-decoration: line-through; + } + .gh-portal-right-arrow { line-height: 1; color: var(--grey8); diff --git a/ghost/portal/src/components/pages/AccountHomePage.js b/ghost/portal/src/components/pages/AccountHomePage.js index 926e3aa07b..3ab76a64d0 100644 --- a/ghost/portal/src/components/pages/AccountHomePage.js +++ b/ghost/portal/src/components/pages/AccountHomePage.js @@ -3,9 +3,10 @@ import MemberAvatar from '../common/MemberGravatar'; import ActionButton from '../common/ActionButton'; import CloseButton from '../common/CloseButton'; import Switch from '../common/Switch'; -import {getMemberSubscription, hasOnlyFreePlan, isComplimentaryMember} from '../../utils/helpers'; +import {getMemberSubscription, getUpdatedOfferPrice, hasOnlyFreePlan, isComplimentaryMember} from '../../utils/helpers'; import {getDateString} from '../../utils/date-time'; import {ReactComponent as LoaderIcon} from '../../images/icons/loader.svg'; +import {ReactComponent as OfferTagIcon} from '../../images/icons/offer-tag.svg'; import {useContext} from 'react'; const React = require('react'); @@ -137,6 +138,25 @@ const UserHeader = () => { ); }; +function getOfferLabel({offer, price, subscriptionStartDate}) { + let offerLabel = ''; + + if (offer) { + const discountDuration = offer.duration; + let durationLabel = ''; + if (discountDuration === 'forever') { + durationLabel = `Forever`; + } else if (discountDuration === 'repeating') { + const durationInMonths = offer.duration_in_months || 0; + let offerStartDate = new Date(subscriptionStartDate); + let offerEndDate = new Date(offerStartDate.setMonth(offerStartDate.getMonth() + durationInMonths)); + durationLabel = `Ends ${getDateString(offerEndDate)}`; + } + offerLabel = `${getUpdatedOfferPrice({offer, price, useFormatted: true})}/${price.interval} - ${durationLabel}`; + } + return offerLabel; +} + const PaidAccountActions = () => { const {member, site, onAction} = useContext(AppContext); @@ -155,19 +175,42 @@ const PaidAccountActions = () => { } }; - const PlanLabel = ({price, isComplimentary}) => { + const PlanLabel = ({price, isComplimentary, subscription}) => { + const { + offer, + start_date: startDate + } = subscription; let label = ''; if (price) { const {amount = 0, currency, interval} = price; label = `${Intl.NumberFormat('en', {currency, style: 'currency'}).format(amount / 100)}/${interval}`; } + let offerLabelStr = getOfferLabel({price, offer, subscriptionStartDate: startDate}); if (isComplimentary) { label = label ? `Complimentary (${label})` : `Complimentary`; } + let oldPriceClassName = ''; + if (offerLabelStr) { + oldPriceClassName = 'old-price'; + } + const OfferLabel = () => { + if (offerLabelStr) { + return ( +

+ + {offerLabelStr} +

+ ); + } + return null; + }; return ( -

- {label} -

+ <> +

+ {label} +

+ + ); }; @@ -216,7 +259,6 @@ const PaidAccountActions = () => { const isComplimentary = isComplimentaryMember({member}); if (subscription || isComplimentary) { const { - plan, price, default_payment_card_last4: defaultCardLast4 } = subscription || {}; @@ -225,7 +267,7 @@ const PaidAccountActions = () => {

Plan

- +
diff --git a/ghost/portal/src/images/icons/offer-tag.svg b/ghost/portal/src/images/icons/offer-tag.svg new file mode 100644 index 0000000000..2c1c48cc66 --- /dev/null +++ b/ghost/portal/src/images/icons/offer-tag.svg @@ -0,0 +1,4 @@ + + + + diff --git a/ghost/portal/src/utils/helpers.js b/ghost/portal/src/utils/helpers.js index db5ef231f2..d86b452a4b 100644 --- a/ghost/portal/src/utils/helpers.js +++ b/ghost/portal/src/utils/helpers.js @@ -502,3 +502,29 @@ export function getPriceIdFromPageQuery({site, pageQuery}) { } return null; } + +export const getOfferOffAmount = ({offer}) => { + if (offer.type === 'fixed') { + return `${getCurrencySymbol(offer.currency)}${offer.amount / 100}`; + } else if (offer.type === 'percent') { + return `${offer.amount}%`; + } + return ''; +}; + +export const getUpdatedOfferPrice = ({offer, price, useFormatted = false}) => { + const originalAmount = price.amount; + let updatedAmount; + if (offer.type === 'fixed' && isSameCurrency(offer.currency, price.currency)) { + updatedAmount = ((originalAmount - offer.amount)) / 100; + updatedAmount = updatedAmount > 0 ? updatedAmount : 0; + } else if (offer.type === 'percent') { + updatedAmount = (originalAmount - ((originalAmount * offer.amount) / 100)) / 100; + } else { + updatedAmount = originalAmount / 100; + } + if (useFormatted) { + return Intl.NumberFormat('en', {currency: price?.currency, style: 'currency'}).format(updatedAmount); + } + return updatedAmount; +};