Skip to content

Commit e9edd04

Browse files
authored
fix(billing): clarify org usage vs personal spend on Plan & usage (#3512)
1 parent 0b69cb9 commit e9edd04

5 files changed

Lines changed: 32 additions & 19 deletions

File tree

packages/core/src/billing/usageDisplay.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,27 @@ describe("formatResetTime", () => {
264264
expected: "Resets shortly",
265265
},
266266
])("$name", ({ resetAt, expected }) => {
267-
const result = formatResetTime(resetAt, NOW);
267+
const result = formatResetTime(resetAt, { now: NOW });
268268
if (expected instanceof RegExp) {
269269
expect(result).toMatch(expected);
270270
} else {
271271
expect(result).toBe(expected);
272272
}
273273
});
274+
275+
it("swaps the leading phrase when a custom label is given", () => {
276+
const opts = { now: NOW, label: "Billing period ends" };
277+
expect(formatResetTime(isoAt(30 * 60 * 1000), opts)).toBe(
278+
"Billing period ends in 30m",
279+
);
280+
expect(formatResetTime(isoAt(4 * 3600 * 1000), opts)).toBe(
281+
"Billing period ends in 4h",
282+
);
283+
expect(formatResetTime(isoAt(-60_000), opts)).toBe(
284+
"Billing period ends shortly",
285+
);
286+
expect(formatResetTime(isoAt(30 * 86400 * 1000), opts)).toMatch(
287+
/^Billing period ends [A-Za-z]+ \d+ at /,
288+
);
289+
});
274290
});

packages/core/src/billing/usageDisplay.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,14 @@ export function isUsageExceeded(usage: UsageOutput): boolean {
8888

8989
export function formatResetTime(
9090
resetAtIso: string,
91-
now: number = Date.now(),
91+
{ now = Date.now(), label = "Resets" }: { now?: number; label?: string } = {},
9292
): string {
9393
const parsed = Date.parse(resetAtIso);
9494
const ms = Number.isNaN(parsed) ? 0 : Math.max(0, parsed - now);
9595

9696
const totalMinutes = Math.ceil(ms / 60_000);
97-
if (totalMinutes <= 0) return "Resets shortly";
98-
if (totalMinutes < 60) return `Resets in ${totalMinutes}m`;
97+
if (totalMinutes <= 0) return `${label} shortly`;
98+
if (totalMinutes < 60) return `${label} in ${totalMinutes}m`;
9999

100100
const totalHours = ms / 3_600_000;
101101
if (totalHours < 24) {
@@ -106,8 +106,8 @@ export function formatResetTime(
106106
minutes = 0;
107107
}
108108
return minutes === 0
109-
? `Resets in ${hours}h`
110-
: `Resets in ${hours}h ${minutes}m`;
109+
? `${label} in ${hours}h`
110+
: `${label} in ${hours}h ${minutes}m`;
111111
}
112112

113113
const target = new Date(now + ms);
@@ -120,5 +120,5 @@ export function formatResetTime(
120120
minute: "2-digit",
121121
timeZoneName: "short",
122122
});
123-
return `Resets ${date} at ${time}`;
123+
return `${label} ${date} at ${time}`;
124124
}

packages/ui/src/features/billing/UsageButton.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@ export function UsageButton() {
6868
meter.kind === "dollars"
6969
? `${formatUsdAmount(meter.usedUsd)} of ${formatUsdAmount(meter.limitUsd)} used`
7070
: `${percent}% used`;
71-
const resetLabel = formatResetTime(
72-
meter.kind === "dollars" ? meter.resetAt : meter.bucket.reset_at,
73-
);
71+
const resetLabel =
72+
meter.kind === "dollars"
73+
? formatResetTime(meter.resetAt, { label: "Billing period ends" })
74+
: formatResetTime(meter.bucket.reset_at);
7475
const breakdownLabel =
7576
meter.kind === "dollars" && meter.breakdown
7677
? formatUsageBreakdown(meter.breakdown)

packages/ui/src/features/settings/sections/PlanUsageSettings.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ import { getBillingUrl } from "@posthog/ui/utils/urls";
3030
import { Badge, Button, Callout, Flex, Spinner, Text } from "@radix-ui/themes";
3131
import { useEffect } from "react";
3232

33-
/**
34-
* Plan & usage under usage-based billing: no seats or plans to manage in-app —
35-
* payment methods, spend limits, and org-level usage live on the PostHog
36-
* billing page. The free-tier meters show the per-user allowance for
37-
* confirmed free-tier orgs; subscribed orgs have no per-user caps to meter.
38-
*/
3933
export function PlanUsageSettings() {
4034
const billingEnabled = useFeatureFlag(BILLING_FLAG);
4135
const spendAnalysisEnabled = useSpendAnalysisEnabled();
@@ -163,7 +157,9 @@ export function PlanUsageSettings() {
163157
</Flex>
164158

165159
<Flex direction="column" gap="3">
166-
<Text className="font-medium text-(--gray-9) text-sm">Usage</Text>
160+
<Text className="font-medium text-(--gray-9) text-sm">
161+
Organization usage
162+
</Text>
167163
{usageLoading ? (
168164
<Flex
169165
align="center"
@@ -178,7 +174,7 @@ export function PlanUsageSettings() {
178174
label={freeTier ? "Monthly free usage" : "Usage this period"}
179175
percent={meter.percent}
180176
valueLabel={`${formatUsdAmount(meter.usedUsd)} of ${formatUsdAmount(meter.limitUsd)}${freeTier ? " included" : ""}`}
181-
detail={`${meter.exceeded ? "Limit exceeded. " : ""}${formatResetTime(meter.resetAt)}`}
177+
detail={`${meter.exceeded ? "Limit exceeded. " : ""}${formatResetTime(meter.resetAt, { label: "Billing period ends" })}`}
182178
breakdown={
183179
meter.breakdown
184180
? { ...meter.breakdown, usedUsd: meter.usedUsd }

packages/ui/src/features/usage/components/SpendAnalysisSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export function SpendAnalysisSection() {
3838
<Flex direction="column" gap="3">
3939
<Flex align="center" justify="between">
4040
<Text className="font-medium text-(--gray-9) text-sm">
41-
Spend analysis
41+
Personal spend analysis
4242
</Text>
4343
<Flex align="center" gap="4">
4444
<WindowSelector value={spendWindow} onChange={setSpendWindow} />

0 commit comments

Comments
 (0)