diff --git a/frontend/__snapshots__/scenes-app-experiments--complete-funnel-experiment.png b/frontend/__snapshots__/scenes-app-experiments--complete-funnel-experiment.png new file mode 100644 index 0000000000000..e2c7fcb5ba238 Binary files /dev/null and b/frontend/__snapshots__/scenes-app-experiments--complete-funnel-experiment.png differ diff --git a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--dark.png b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--dark.png index d3c40fcac13be..1b97153aa1584 100644 Binary files a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--dark.png and b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--dark.png differ diff --git a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--light.png b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--light.png index fded7d3bbff94..a37f2399a96ba 100644 Binary files a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--light.png and b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2--light.png differ diff --git a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--dark.png b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--dark.png index e849eb85f0d41..0c6ff90962bfe 100644 Binary files a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--dark.png and b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--dark.png differ diff --git a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--light.png b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--light.png index 058db6dcc9e1e..54461bdf672d3 100644 Binary files a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--light.png and b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount--light.png differ diff --git a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount.png b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount.png new file mode 100644 index 0000000000000..7cfdfd4aabb5e Binary files /dev/null and b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2-with-discount.png differ diff --git a/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2.png b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2.png new file mode 100644 index 0000000000000..68a5a938fe618 Binary files /dev/null and b/frontend/__snapshots__/scenes-other-billing-v2--billing-v-2.png differ diff --git a/frontend/src/scenes/billing/Billing.tsx b/frontend/src/scenes/billing/Billing.tsx index 755e8da0eea36..6aa63320c5717 100644 --- a/frontend/src/scenes/billing/Billing.tsx +++ b/frontend/src/scenes/billing/Billing.tsx @@ -1,12 +1,15 @@ +import './Billing.scss' + import { LemonButton, LemonDivider, LemonInput, Link } from '@posthog/lemon-ui' import clsx from 'clsx' import { useActions, useValues } from 'kea' import { Field, Form } from 'kea-forms' +import { SurprisedHog } from 'lib/components/hedgehogs' import { PageHeader } from 'lib/components/PageHeader' import { supportLogic } from 'lib/components/Support/supportLogic' import { dayjs } from 'lib/dayjs' import { useResizeBreakpoints } from 'lib/hooks/useResizeObserver' -import { IconPlus } from 'lib/lemon-ui/icons' +import { IconCheckCircleOutline, IconPlus } from 'lib/lemon-ui/icons' import { LemonBanner } from 'lib/lemon-ui/LemonBanner' import { LemonLabel } from 'lib/lemon-ui/LemonLabel/LemonLabel' import { SpinnerOverlay } from 'lib/lemon-ui/Spinner/Spinner' @@ -38,6 +41,8 @@ export function Billing(): JSX.Element { showLicenseDirectInput, isActivateLicenseSubmitting, isUnlicensedDebug, + over20kAnnual, + isAnnualPlan, } = useValues(billingLogic) const { reportBillingV2Shown } = useActions(billingLogic) const { preflight } = useValues(preflightLogic) @@ -125,24 +130,7 @@ export function Billing(): JSX.Element { return (
- {!isOnboarding && ( -
- - {billing?.has_active_subscription && ( -
- - Manage card details - -
- )} -
- )} + {!isOnboarding && } {showLicenseDirectInput && ( <>
@@ -174,99 +162,174 @@ export function Billing(): JSX.Element {
)} +
- {!isOnboarding && billing?.billing_period && ( -
-
-
-

- {billing?.has_active_subscription ? 'Billing period' : 'Cycle'}:{' '} - {billing.billing_period.current_period_start.format('LL')} to{' '} - {billing.billing_period.current_period_end.format('LL')} ( - {billing.billing_period.current_period_end.diff(dayjs(), 'days')} days remaining) -

- {!billing.has_active_subscription && ( -

- Monthly free allocation resets at the end of the cycle. -

- )} -
- - {billing?.has_active_subscription && ( - <> - - Current bill total - -
- ${billing.current_total_amount_usd_after_discount} -
- {billing.discount_percent && ( -
-

- {billing.discount_percent}% off discount applied -

-
+
+
+ {!isOnboarding && billing?.billing_period && ( +
+
+ {billing?.has_active_subscription && ( + <> + + Current bill total + +
+ ${billing.current_total_amount_usd_after_discount} +
+ {billing.discount_percent && ( +
+

+ {billing.discount_percent}% off discount + applied +

+
+ )} + {billing.discount_amount_usd && ( +
+

+ + + $ + {parseInt(billing.discount_amount_usd).toLocaleString()} + {' '} + + remaining credits applied to your bill. +

+
+ )} + )} - {billing.discount_amount_usd && ( -
-

- - - ${parseInt(billing.discount_amount_usd).toLocaleString()} - {' '} - - remaining credits applied to your bill. +

+

+ {billing?.has_active_subscription ? 'Billing period' : 'Cycle'}:{' '} + {billing.billing_period.current_period_start.format('LL')} to{' '} + {billing.billing_period.current_period_end.format('LL')} ( + {billing.billing_period.current_period_end.diff(dayjs(), 'days')} days + remaining) +

+ {!billing.has_active_subscription && ( +

+ Monthly free allocation resets at the end of the cycle.

+ )} +
+
+
+ )} + + {!cloudOrDev && (billing?.license?.plan || !billing?.has_active_subscription) && ( +
+ {!cloudOrDev && billing?.license?.plan ? ( +
+
+ {capitalizeFirstLetter(billing.license.plan)} license
- )} - - )} -
-
- )} + + Please contact sales@posthog.com{' '} + if you would like to make any changes to your license. + +
+ ) : null} -
- {!cloudOrDev && billing?.license?.plan ? ( -
-
- {capitalizeFirstLetter(billing.license.plan)} license + {!cloudOrDev && !billing?.has_active_subscription ? ( +

+ Self-hosted licenses are no longer available for purchase. Please contact{' '} + sales@posthog.com to discuss options. +

+ ) : null}
- - Please contact sales@posthog.com if you would - like to make any changes to your license. - -
- ) : null} + )} +
- {!cloudOrDev && !billing?.has_active_subscription ? ( -

- Self-hosted licenses are no longer available for purchase. Please contact{' '} - sales@posthog.com to discuss options. -

- ) : null} + {!isOnboarding && billing?.has_active_subscription && ( +
+ + Manage card details and view past invoices + +
+ )}
+ {!isOnboarding && !isAnnualPlan && over20kAnnual && ( +
+
+

You've unlocked enterprise-grade perks:

+
    +
  • + + + Save 20% by switching to up-front annual billing + +
  • +
  • + + + Get discounts on bundled subscriptions to multiple products + +
  • +
  • + + + Get customized training for you and your team + +
  • +
  • + + + Get dedicated support via private Slack channel + +
  • +
  • + + + We'll even send you awesome free merch + +
  • +
+
+ + Let's chat + +
+
+
+ +
+
+ )}
diff --git a/frontend/src/scenes/billing/billingLogic.ts b/frontend/src/scenes/billing/billingLogic.ts index ec549af6fe264..d3de24075c4ce 100644 --- a/frontend/src/scenes/billing/billingLogic.ts +++ b/frontend/src/scenes/billing/billingLogic.ts @@ -162,9 +162,32 @@ export const billingLogic = kea([ return projectedTotal }, ], + over20kAnnual: [ + (s) => [s.billing, s.preflight, s.projectedTotalAmountUsd], + (billing, preflight, projectedTotalAmountUsd) => { + if (!billing || !preflight?.cloud) { + return + } + if ( + billing.current_total_amount_usd_after_discount && + (parseFloat(billing.current_total_amount_usd_after_discount) > 1666 || + projectedTotalAmountUsd > 1666) && + billing.billing_period?.interval === 'month' + ) { + return true + } + return + }, + ], + isAnnualPlan: [ + (s) => [s.billing], + (billing) => { + return billing?.billing_period?.interval === 'year' + }, + ], billingAlert: [ - (s) => [s.billing, s.preflight, s.projectedTotalAmountUsd, s.productSpecificAlert], - (billing, preflight, projectedTotalAmountUsd, productSpecificAlert): BillingAlertConfig | undefined => { + (s) => [s.billing, s.preflight, s.productSpecificAlert], + (billing, preflight, productSpecificAlert): BillingAlertConfig | undefined => { if (productSpecificAlert) { return productSpecificAlert } @@ -228,21 +251,6 @@ export const billingLogic = kea([ } 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', - } - } }, ], }), diff --git a/frontend/src/styles/utilities.scss b/frontend/src/styles/utilities.scss index 04d595ea54910..dd4850969830f 100644 --- a/frontend/src/styles/utilities.scss +++ b/frontend/src/styles/utilities.scss @@ -1408,3 +1408,7 @@ $decorations: underline, overline, line-through, no-underline; .aspect-video { aspect-ratio: 16 / 9; } + +.-scale-x-1 { + transform: scaleX(-1); +}