From f8fa925a5d17c651c44df2bdd908687e4ae67772 Mon Sep 17 00:00:00 2001 From: Piotr Monwid-Olechnowicz Date: Sat, 21 Feb 2026 18:51:22 +0100 Subject: [PATCH 1/2] quick draft pricing change to 5B --- .../app/src/pages/organization-subscription-manage.tsx | 10 ++++++---- packages/web/docs/src/components/pricing/index.tsx | 2 +- .../web/docs/src/components/pricing/pricing-slider.tsx | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/web/app/src/pages/organization-subscription-manage.tsx b/packages/web/app/src/pages/organization-subscription-manage.tsx index d3f595c5d67..e7342a195d5 100644 --- a/packages/web/app/src/pages/organization-subscription-manage.tsx +++ b/packages/web/app/src/pages/organization-subscription-manage.tsx @@ -379,16 +379,18 @@ function Inner(props: {
1M - 100M - 200M - 300M + 1B + 2B + 3B + 4B + 5B
diff --git a/packages/web/docs/src/components/pricing/index.tsx b/packages/web/docs/src/components/pricing/index.tsx index a189aae220f..1ac25c2c9f1 100644 --- a/packages/web/docs/src/components/pricing/index.tsx +++ b/packages/web/docs/src/components/pricing/index.tsx @@ -86,7 +86,7 @@ export function Pricing({ className }: { className?: string }): ReactElement { { - const newPlan = value === 1 ? 'Hobby' : value < 280 ? 'Pro' : 'Enterprise'; + const newPlan = value === 1 ? 'Hobby' : value < 4800 ? 'Pro' : 'Enterprise'; if (newPlan !== highlightedPlan) { setHighlightedPlan(newPlan); if (!scrollviewRef.current) return; diff --git a/packages/web/docs/src/components/pricing/pricing-slider.tsx b/packages/web/docs/src/components/pricing/pricing-slider.tsx index b0df47aafab..6b25234d10b 100644 --- a/packages/web/docs/src/components/pricing/pricing-slider.tsx +++ b/packages/web/docs/src/components/pricing/pricing-slider.tsx @@ -13,7 +13,7 @@ export function PricingSlider({ onChange: (value: number) => void; }) { const min = 1; - const max = 300; + const max = 5000; const [popoverOpen, setPopoverOpen] = useState(false); const rootRef = useRef(null); @@ -64,7 +64,7 @@ export function PricingSlider({ onChange(value); }} /> - {max}M + 5B From 70c9bd68c0cfdf9a2210cbd5a652607b2390a964 Mon Sep 17 00:00:00 2001 From: Piotr Monwid-Olechnowicz Date: Sat, 21 Feb 2026 18:58:19 +0100 Subject: [PATCH 2/2] Format with billions --- .../organization/billing/PlanSummary.tsx | 8 +++---- .../organization/billing/helpers.ts | 9 +++++++ .../src/components/pricing/pricing-slider.tsx | 24 +++++++++++++++---- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/packages/web/app/src/components/organization/billing/PlanSummary.tsx b/packages/web/app/src/components/organization/billing/PlanSummary.tsx index 68d11dd2adb..839520db9c2 100644 --- a/packages/web/app/src/components/organization/billing/PlanSummary.tsx +++ b/packages/web/app/src/components/organization/billing/PlanSummary.tsx @@ -2,7 +2,7 @@ import { ReactElement, ReactNode } from 'react'; import { Stat, Table, TBody, Td, TFoot, Th, THead, Tr } from '@/components/v2'; import { FragmentType, graphql, useFragment } from '@/gql'; import { BillingPlanType } from '@/gql/graphql'; -import { CurrencyFormatter } from './helpers'; +import { CurrencyFormatter, formatOperations } from './helpers'; const PriceEstimationTable_PlanFragment = graphql(` fragment PriceEstimationTable_PlanFragment on BillingPlan { @@ -48,7 +48,7 @@ function PriceEstimationTable(props: { Included Operations (free) - {includedOperationsInMillions}M + {formatOperations(includedOperationsInMillions)} {CurrencyFormatter.format(0)} {CurrencyFormatter.format(0)} @@ -56,7 +56,7 @@ function PriceEstimationTable(props: { {plan.planType === BillingPlanType.Pro && ( Operations - {additionalOperations}M + {formatOperations(additionalOperations)} {CurrencyFormatter.format(plan.pricePerOperationsUnit ?? 0)} {CurrencyFormatter.format(operationsTotal)} @@ -114,7 +114,7 @@ export function PlanSummary({ Operations Limit up to - {operationsRateLimit}M + {formatOperations(operationsRateLimit)} per month diff --git a/packages/web/app/src/components/organization/billing/helpers.ts b/packages/web/app/src/components/organization/billing/helpers.ts index ac2981a70f2..ec83a205a15 100644 --- a/packages/web/app/src/components/organization/billing/helpers.ts +++ b/packages/web/app/src/components/organization/billing/helpers.ts @@ -9,3 +9,12 @@ export const DateFormatter = Intl.DateTimeFormat('en', { month: 'short', day: 'numeric', }); + +/** Format millions of operations as "500M" or "2.5B" */ +export function formatOperations(millions: number): string { + if (millions >= 1000) { + const b = parseFloat((millions / 1000).toFixed(3)); + return `${b}B`; + } + return `${millions}M`; +} diff --git a/packages/web/docs/src/components/pricing/pricing-slider.tsx b/packages/web/docs/src/components/pricing/pricing-slider.tsx index 6b25234d10b..93792deee2b 100644 --- a/packages/web/docs/src/components/pricing/pricing-slider.tsx +++ b/packages/web/docs/src/components/pricing/pricing-slider.tsx @@ -4,6 +4,16 @@ import { CallToAction, cn } from '@theguild/components'; import { BookIcon } from '../book-icon'; import { Slider } from '../slider'; +function formatOps(millions: number): { label: string; chars: number } { + if (millions >= 1000) { + const b = parseFloat((millions / 1000).toFixed(3)); + const label = `${b} B`; + return { label, chars: label.length - 1 }; + } + const label = `${millions} M`; + return { label, chars: label.length - 1 }; +} + export function PricingSlider({ className, onChange, @@ -16,26 +26,27 @@ export function PricingSlider({ const max = 5000; const [popoverOpen, setPopoverOpen] = useState(false); + const [opsLabel, setOpsLabel] = useState(() => formatOps(min).label); const rootRef = useRef(null); return (
-
-
- M +
+
+ {opsLabel}
How many @@ -60,7 +71,10 @@ export function PricingSlider({ counter="after:content-['$'_counter(price)_'_/_month'] after:[counter-set:price_calc(var(--price))]" onChange={event => { const value = event.currentTarget.valueAsNumber; + const display = formatOps(value); rootRef.current!.style.setProperty('--ops', `${value}`); + rootRef.current!.style.setProperty('--ops-chars', `${display.chars}`); + setOpsLabel(display.label); onChange(value); }} />