Skip to content

Commit

Permalink
feat: make addons ui work for personless (#22290)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
raquelmsmith and github-actions[bot] authored May 22, 2024
1 parent 90155c4 commit 24ec9e8
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 21 deletions.
1 change: 1 addition & 0 deletions frontend/src/scenes/billing/BillingProduct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ export const BillingProduct = ({ product }: { product: BillingProductV2Type }):
<h4 className="my-4">Addons</h4>
<div className="gap-y-4 flex flex-col">
{product.addons
// TODO: enhanced_persons: remove this filter
.filter((addon) => !addon.inclusion_only)
.map((addon, i) => {
return <BillingProductAddon key={i} addon={addon} />
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/scenes/billing/BillingProductAddon.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IconCheckCircle, IconDocument, IconPlus } from '@posthog/icons'
import { LemonButton, LemonSelectOptions, LemonTag, Tooltip } from '@posthog/lemon-ui'
import { LemonButton, LemonSelectOptions, LemonTag, Link, Tooltip } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { UNSUBSCRIBE_SURVEY_ID } from 'lib/constants'
import { More } from 'lib/lemon-ui/LemonButton/More'
Expand Down Expand Up @@ -35,6 +35,10 @@ export const BillingProductAddon = ({ addon }: { addon: BillingProductV2AddonTyp
// Filter out the addon itself from the features list
const addonFeatures = addon.features?.filter((feature) => feature.name !== addon.name)

const is_enhanced_persons_og_customer =
addon.type === 'enhanced_persons' &&
addon.plans?.find((plan) => plan.plan_key === 'addon-20240404-og-customers')

return (
<div className="bg-side rounded p-6 flex flex-col" ref={productRef}>
<div className="flex justify-between gap-x-4">
Expand All @@ -60,6 +64,18 @@ export const BillingProductAddon = ({ addon }: { addon: BillingProductV2AddonTyp
)}
</div>
<p className="ml-0 mb-0">{addon.description}</p>
{is_enhanced_persons_og_customer && (
<p className="mt-2 mb-0">
<Link
to="https://posthog.com/changelog/2024#person-profiles-addon"
className="italic"
target="_blank"
targetBlankIcon
>
Why is this here?{' '}
</Link>
</p>
)}
</div>
</div>
<div className="ml-4 mr-4 mt-2 self-center flex items-center gap-x-3 whitespace-nowrap">
Expand Down
109 changes: 89 additions & 20 deletions frontend/src/scenes/billing/PlanComparison.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { UNSUBSCRIBE_SURVEY_ID } from 'lib/constants'
import { dayjs } from 'lib/dayjs'
import { Tooltip } from 'lib/lemon-ui/Tooltip'
import { eventUsageLogic } from 'lib/utils/eventUsageLogic'
import React from 'react'
import React, { useState } from 'react'
import { getProductIcon } from 'scenes/products/Products'
import { urls } from 'scenes/urls'
import useResizeObserver from 'use-resize-observer'
Expand Down Expand Up @@ -55,10 +55,13 @@ export function PlanIcon({
)
}

const getProductTiers = (
plan: BillingV2PlanType,
const PricingTiers = ({
plan,
product,
}: {
plan: BillingV2PlanType
product: BillingProductV2Type | BillingProductV2AddonType
): JSX.Element => {
}): JSX.Element => {
const { width, ref: tiersRef } = useResizeObserver()
const tiers = plan?.tiers

Expand Down Expand Up @@ -262,43 +265,74 @@ export const PlanComparison = ({
<p className="ml-0 text-xs mt-1">Priced per {product.unit}</p>
</th>
{plans?.map((plan) => (
<td key={`${plan.plan_key}-tiers-td`}>{getProductTiers(plan, product)}</td>
<td key={`${plan.plan_key}-tiers-td`}>
<PricingTiers plan={plan} product={product} />
</td>
))}
</tr>
)}
<tr>
<td />
{upgradeButtons}
</tr>
{includeAddons && product.addons.length > 0 && (
<tr>
<th colSpan={1} className="PlanTable__th__section rounded text-left">
<h3 className="mt-6 mb-6">Available add-ons:</h3>
</th>
</tr>
)}
{includeAddons &&
product.addons?.map((addon) => {
// TODO: enhanced_persons: addon will show up here when we add a price plan. Make sure this can handle it.
return addon.tiered ? (
<tr key={addon.name + 'pricing-row'} className="PlanTable__tr__border">
<th scope="row">
<p className="ml-0">
<span className="font-bold">{addon.name}</span>
<LemonTag type="completion" className="ml-2">
addon
</LemonTag>
<Tooltip title={addon.description}>
<span className="font-bold cursor-default">{addon.name}</span>
</Tooltip>
<Tooltip
title={
addon.inclusion_only
? 'Automatically charged based on SDK config options and usage.'
: 'If subscribed, charged on all usage.'
}
>
<LemonTag
type={addon.inclusion_only ? 'option' : 'primary'}
className="ml-2"
>
{addon.inclusion_only ? 'config' : 'add-on'}
</LemonTag>
</Tooltip>
</p>
<p className="ml-0 text-xs text-muted mt-1">Priced per {addon.unit}</p>
</th>
{plans?.map((plan) =>
// If the plan is free, the addon isn't available
plan.free_allocation && !plan.tiers ? (
{plans?.map((plan, i) => {
// If the parent plan is free, the addon isn't available
return !addon.inclusion_only ? (
plan.free_allocation && !plan.tiers ? (
<td key={`${addon.name}-free-tiers-td`}>
<p className="text-muted text-xs">Not available on this plan.</p>
</td>
) : (
<td key={`${addon.type}-tiers-td`}>
<AddonPlanTiers plan={addon.plans?.[0]} addon={addon} />
</td>
)
) : plan.free_allocation && !plan.tiers ? (
<td key={`${addon.name}-free-tiers-td`}>
<p className="text-muted text-xs">Not available on this plan.</p>
<PricingTiers plan={plan} product={product} />
</td>
) : (
<td key={`${addon.type}-tiers-td`}>
{getProductTiers(addon.plans?.[0], addon)}
<AddonPlanTiers plan={addon.plans?.[i]} addon={addon} />
</td>
)
)}
})}
</tr>
) : null
})}
<tr>
<td />
{upgradeButtons}
</tr>
<tr>
<th colSpan={1} className="PlanTable__th__section rounded text-left">
<h3 className="mt-6 mb-2">Product Features:</h3>
Expand Down Expand Up @@ -465,3 +499,38 @@ export const PlanComparisonModal = ({
</LemonModal>
)
}

const AddonPlanTiers = ({
plan,
addon,
}: {
plan: BillingV2PlanType
addon: BillingProductV2AddonType
}): JSX.Element => {
const [showTiers, setShowTiers] = useState(false)

return showTiers ? (
<>
<PricingTiers plan={plan} product={addon} />
<p className="mb-0">
<Link onClick={() => setShowTiers(false)} className="text-xs">
Hide volume discounts
</Link>
</p>
</>
) : (
<>
<p className="mb-1">
<b>
First {convertLargeNumberToWords(plan?.tiers?.[0].up_to || 0, null)} {addon.unit}s free
</b>
, then just ${plan?.tiers?.[1].unit_amount_usd}.
</p>
<p className="mb-0">
<Link onClick={() => setShowTiers(true)} className="text-xs">
Show volume discounts
</Link>
</p>
</>
)
}

0 comments on commit 24ec9e8

Please sign in to comment.