Skip to content

Commit

Permalink
feat: show CTA for annual plan if over $1k/mo (PostHog#18049)
Browse files Browse the repository at this point in the history
* show CTA for annual plan if over $1k/mo

* let it be dismissed

* Update UI snapshots for `chromium` (1)

* up front

* send event whn clicked

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
2 people authored and Justicea83 committed Oct 25, 2023
1 parent 5e4da88 commit cf97074
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 10 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/scenes-other-billing-v2--billing-v-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions frontend/src/lib/components/BillingAlertsV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { LemonBanner } from 'lib/lemon-ui/LemonBanner'

export function BillingAlertsV2(): JSX.Element | null {
const { billingAlert } = useValues(billingLogic)
const { reportBillingAlertShown } = useActions(billingLogic)
const { reportBillingAlertShown, reportBillingAlertActionClicked } = useActions(billingLogic)
const { currentLocation } = useValues(router)
const [alertHidden, setAlertHidden] = useState(false)

Expand All @@ -21,21 +21,27 @@ export function BillingAlertsV2(): JSX.Element | null {
return null
}

const showButton = currentLocation.pathname !== urls.organizationBilling()
const showButton = billingAlert.contactSupport || currentLocation.pathname !== urls.organizationBilling()

const buttonProps = billingAlert.contactSupport
? {
to: 'mailto:[email protected]',
children: 'Contact support',
children: billingAlert.buttonCTA || 'Contact support',
onClick: () => reportBillingAlertActionClicked(billingAlert),
}
: {
to: urls.organizationBilling(),
children: 'Manage billing',
onClick: () => reportBillingAlertActionClicked(billingAlert),
}
: { to: urls.organizationBilling(), children: 'Manage billing' }

return (
<div className="my-4">
<LemonBanner
type={billingAlert.status}
action={showButton ? buttonProps : undefined}
onClose={billingAlert.status !== 'error' ? () => setAlertHidden(true) : undefined}
dismissKey={billingAlert.dismissKey}
>
<b>{billingAlert.title}</b>
<br />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/billing/Billing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ export function Billing(): JSX.Element {
</div>
</div>

<div className="flex justify-between">
<div className="flex justify-between mt-4">
<h2>Products</h2>
{isOnboarding && upgradeAllProductsLink && (
<LemonButton
Expand Down
45 changes: 40 additions & 5 deletions frontend/src/scenes/billing/billingLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ export const ALLOCATION_THRESHOLD_BLOCK = 1.2 // Threshold to block usage
export interface BillingAlertConfig {
status: 'info' | 'warning' | 'error'
title: string
message: string
message?: string
contactSupport?: boolean
buttonCTA?: string
dismissKey?: string
}

const parseBillingResponse = (data: Partial<BillingV2Type>): BillingV2Type => {
Expand Down Expand Up @@ -54,6 +56,7 @@ export const billingLogic = kea<billingLogicType>([
actions({
setShowLicenseDirectInput: (show: boolean) => ({ show }),
reportBillingAlertShown: (alertConfig: BillingAlertConfig) => ({ alertConfig }),
reportBillingAlertActionClicked: (alertConfig: BillingAlertConfig) => ({ alertConfig }),
reportBillingV2Shown: true,
registerInstrumentationProps: true,
setRedirectPath: true,
Expand Down Expand Up @@ -130,9 +133,22 @@ export const billingLogic = kea<billingLogicType>([
(s) => [s.preflight, s.billing],
(preflight, billing): boolean => !!preflight?.is_debug && !billing?.billing_period,
],
projectedTotalAmountUsd: [
(s) => [s.billing],
(billing: BillingV2Type): number => {
if (!billing) {
return 0
}
let projectedTotal = 0
for (const product of billing.products || []) {
projectedTotal += parseFloat(product.projected_amount_usd || '0')
}
return projectedTotal
},
],
billingAlert: [
(s) => [s.billing, s.preflight],
(billing, preflight): BillingAlertConfig | undefined => {
(s) => [s.billing, s.preflight, s.projectedTotalAmountUsd],
(billing, preflight, projectedTotalAmountUsd): BillingAlertConfig | undefined => {
if (!billing || !preflight?.cloud) {
return
}
Expand Down Expand Up @@ -163,7 +179,7 @@ export const billingLogic = kea<billingLogicType>([
}
}

const productOverLimit = billing.products?.find((x) => {
const productOverLimit = billing.products?.find((x: BillingProductV2Type) => {
return x.percentage_usage > 1
})

Expand All @@ -190,6 +206,21 @@ export const billingLogic = kea<billingLogicType>([
)}% of your ${productApproachingLimit.usage_key.toLowerCase()} allocation.`,
}
}

if (
billing.current_total_amount_usd_after_discount &&
(parseFloat(billing.current_total_amount_usd_after_discount) > 1000 ||
projectedTotalAmountUsd > 1000) &&
billing.billing_period?.interval === 'month'
) {
return {
status: 'info',
title: `Switch to annual up-front billing to save up to 20% on your bill.`,
contactSupport: true,
buttonCTA: 'Contact sales',
dismissKey: 'annual-billing-cta',
}
}
},
],
}),
Expand Down Expand Up @@ -231,6 +262,11 @@ export const billingLogic = kea<billingLogicType>([
...alertConfig,
})
},
reportBillingAlertActionClicked: ({ alertConfig }) => {
posthog.capture('billing alert action clicked', {
...alertConfig,
})
},
loadBillingSuccess: () => {
if (
router.values.location.pathname.includes('/organization/billing') &&
Expand Down Expand Up @@ -276,7 +312,6 @@ export const billingLogic = kea<billingLogicType>([
}
},
})),

afterMount(({ actions }) => {
actions.loadBilling()
}),
Expand Down

0 comments on commit cf97074

Please sign in to comment.