@growth-operations/ui-shared 1.13.0 → 1.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -358,8 +358,13 @@ function CreditsBilling({ context, state, appKey, openIframe = null }) {
|
|
|
358
358
|
// current tier and disable everything ranked below it ("Talk to sales to
|
|
359
359
|
// switch") — the backend independently re-validates the same upgrade
|
|
360
360
|
// direction (start_upgrade_redirect's tier_order check), so this is safe
|
|
361
|
-
// even if currentOrder were ever wrong. Downgrade
|
|
362
|
-
//
|
|
361
|
+
// even if currentOrder were ever wrong. Downgrade is intentionally NOT
|
|
362
|
+
// self-serve (policy, not a Stripe portal gap): PlanCard's own
|
|
363
|
+
// "Talk to sales to switch" is the one and only downgrade path. Cancel /
|
|
364
|
+
// payment method / invoices still go through the Stripe Customer Portal
|
|
365
|
+
// link below — the footnote must not imply Manage subscription can also
|
|
366
|
+
// downgrade (some apps' Stripe portal config has subscription_update
|
|
367
|
+
// disabled anyway, so it silently couldn't even if we wanted it to).
|
|
363
368
|
if (onPaidPlan) {
|
|
364
369
|
const plans = state?.plans ?? [];
|
|
365
370
|
const currentOrder = plans.find((p) => p.current)?.tier_order;
|
|
@@ -388,7 +393,7 @@ function CreditsBilling({ context, state, appKey, openIframe = null }) {
|
|
|
388
393
|
endpoint="upgrade/start"
|
|
389
394
|
ctaLabel="Upgrade to"
|
|
390
395
|
heading="Your plan"
|
|
391
|
-
footnote="Upgrade any time — the new tier applies immediately with prorated billing. To move to a lower tier, cancel
|
|
396
|
+
footnote="Upgrade any time — the new tier applies immediately with prorated billing. To move to a lower tier, contact us. Use Manage subscription above to cancel or update your payment method."
|
|
392
397
|
openIframe={openIframe}
|
|
393
398
|
/>
|
|
394
399
|
) : (
|
package/src/home/CreditMeter.jsx
CHANGED
|
@@ -24,14 +24,31 @@ export function CreditMeter({ entitlement, creditMeter }) {
|
|
|
24
24
|
const used = meter?.used ?? ent?.used ?? 0;
|
|
25
25
|
const remaining = meter?.remaining ?? ent?.remaining ?? Math.max(granted - used, 0);
|
|
26
26
|
|
|
27
|
+
// A paid plan is NEVER blocked — exceeding the included bucket is overage,
|
|
28
|
+
// not depletion (action_allowed_by_portal/consume_credits never gate a
|
|
29
|
+
// paid plan; see common.entitlements.credits.to_entitlement). So `depleted`
|
|
30
|
+
// must not fall back to raw `remaining <= 0` on a paid plan the way it does
|
|
31
|
+
// on the free tier — that raw check is exactly what showed a paying,
|
|
32
|
+
// already-subscribed customer a blocking "Depleted"/"out of credits" panel
|
|
33
|
+
// (confirmed live 2026-09-02). `over_included` is the distinct paid-plan
|
|
34
|
+
// signal for "you've used your included credits, extra usage is overage".
|
|
35
|
+
const onPaidPlan = !!ent?.plan;
|
|
27
36
|
const lowThreshold = ent?.low_threshold ?? 0;
|
|
28
|
-
const depleted = ent?.depleted === true || remaining <= 0;
|
|
29
|
-
const
|
|
37
|
+
const depleted = !onPaidPlan && (ent?.depleted === true || remaining <= 0);
|
|
38
|
+
const overIncluded =
|
|
39
|
+
onPaidPlan && (ent?.over_included === true || used > granted);
|
|
40
|
+
const low = !depleted && !overIncluded && remaining <= lowThreshold;
|
|
30
41
|
|
|
31
|
-
// healthy green / low yellow / depleted red.
|
|
32
|
-
const variant = depleted ? "error" : low ? "warning" : "success";
|
|
33
|
-
const tagVariant = depleted ? "danger" : low ? "warning" : "success";
|
|
34
|
-
const tagLabel = depleted
|
|
42
|
+
// healthy green / low or overage yellow / depleted red.
|
|
43
|
+
const variant = depleted ? "error" : overIncluded || low ? "warning" : "success";
|
|
44
|
+
const tagVariant = depleted ? "danger" : overIncluded || low ? "warning" : "success";
|
|
45
|
+
const tagLabel = depleted
|
|
46
|
+
? "Depleted"
|
|
47
|
+
: overIncluded
|
|
48
|
+
? "Over included"
|
|
49
|
+
: low
|
|
50
|
+
? "Running low"
|
|
51
|
+
: "Healthy";
|
|
35
52
|
|
|
36
53
|
const grantDaysLeft = ent?.grant_expires_at ? daysUntil(ent.grant_expires_at) : null;
|
|
37
54
|
|
|
@@ -65,15 +82,23 @@ export function CreditMeter({ entitlement, creditMeter }) {
|
|
|
65
82
|
</Text>
|
|
66
83
|
)}
|
|
67
84
|
|
|
68
|
-
{(depleted || low) && (
|
|
85
|
+
{(depleted || overIncluded || low) && (
|
|
69
86
|
<Alert
|
|
70
|
-
title={
|
|
87
|
+
title={
|
|
88
|
+
depleted
|
|
89
|
+
? "You're out of credits"
|
|
90
|
+
: overIncluded
|
|
91
|
+
? "You've used your included credits"
|
|
92
|
+
: "Running low on credits"
|
|
93
|
+
}
|
|
71
94
|
variant={variant}
|
|
72
95
|
>
|
|
73
96
|
<Text>
|
|
74
97
|
{depleted
|
|
75
98
|
? "Pick a plan or buy more credits to keep going."
|
|
76
|
-
:
|
|
99
|
+
: overIncluded
|
|
100
|
+
? "Extra usage this period is billed as overage at your plan's per-credit rate."
|
|
101
|
+
: "You're getting close to your limit — pick a plan to top up."}
|
|
77
102
|
</Text>
|
|
78
103
|
</Alert>
|
|
79
104
|
)}
|