@growth-operations/ui-shared 1.21.1 → 1.21.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
package/src/home/HealthHero.jsx
CHANGED
|
@@ -26,8 +26,11 @@ export function HealthHero({ appName, state }) {
|
|
|
26
26
|
// Plan-fit reinforcement: a healthy verdict on the right plan gets the
|
|
27
27
|
// extra reassurance line; upgrade_recommended is carried by health
|
|
28
28
|
// v2's "attention" reasons + the PlanFitBanner, not here.
|
|
29
|
+
// Dual-read: base nests plan_fit under payload.state; self-hosted
|
|
30
|
+
// backends MAY emit it top-level (same pattern as planFitOf).
|
|
31
|
+
const planFit = state.state?.plan_fit ?? state.plan_fit;
|
|
29
32
|
const onRightPlan =
|
|
30
|
-
health.level === "healthy" &&
|
|
33
|
+
health.level === "healthy" && planFit?.verdict === "right_plan";
|
|
31
34
|
return (
|
|
32
35
|
<Flex direction="column" gap="small">
|
|
33
36
|
{name && <Heading>{name}</Heading>}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Flex, Tile, Text, ProgressBar } from "@hubspot/ui-extensions";
|
|
3
|
-
import {
|
|
3
|
+
import { periodComparisonOf } from "../lib/homeBlocks";
|
|
4
4
|
|
|
5
5
|
// The post-checklist Home usage block: the last full billing period vs the
|
|
6
6
|
// current period-to-date, side by side — one bar per period (shared
|
|
@@ -41,7 +41,9 @@ function PeriodColumn({ period, maxTotal }) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export function PeriodComparison({ state }) {
|
|
44
|
-
|
|
44
|
+
// periodComparisonOf dual-reads payload.state.period_comparison (base) ??
|
|
45
|
+
// payload.period_comparison (self-hosted).
|
|
46
|
+
const view = periodComparisonOf(state);
|
|
45
47
|
if (!view) return null;
|
|
46
48
|
|
|
47
49
|
return (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Text, Alert } from "@hubspot/ui-extensions";
|
|
3
|
-
import {
|
|
3
|
+
import { planFitOf } from "../lib/homeBlocks";
|
|
4
4
|
|
|
5
5
|
// The plan-fit savings banner: when state.plan_fit.verdict is
|
|
6
6
|
// "upgrade_recommended", tell the customer what staying on their current tier
|
|
@@ -14,7 +14,10 @@ import { resolvePlanFit } from "../lib/homeBlocks";
|
|
|
14
14
|
// Renders nothing when the block is absent or the verdict isn't
|
|
15
15
|
// upgrade_recommended.
|
|
16
16
|
export function PlanFitBanner({ state }) {
|
|
17
|
-
|
|
17
|
+
// planFitOf dual-reads payload.state.plan_fit (base) ?? payload.plan_fit
|
|
18
|
+
// (self-hosted) — a top-level-only read left this banner dead on every
|
|
19
|
+
// base-hosted app (found 2026-10-13).
|
|
20
|
+
const fit = planFitOf(state);
|
|
18
21
|
if (!fit || fit.kind !== "upgrade_recommended") return null;
|
|
19
22
|
|
|
20
23
|
return (
|
package/src/index.js
CHANGED
|
@@ -53,6 +53,7 @@ export { useStrictModeEffect } from "./lib/useStrictModeEffect";
|
|
|
53
53
|
export { resolveFeatureUsage, featureUsageOf } from "./lib/featureUsage";
|
|
54
54
|
export {
|
|
55
55
|
hasTopUpBank,
|
|
56
|
+
creditsBlockOf,
|
|
56
57
|
resolveCreditMeter,
|
|
57
58
|
resolveBillingBanner,
|
|
58
59
|
parseLimitInput,
|
|
@@ -61,7 +62,9 @@ export {
|
|
|
61
62
|
TRIAL_BANNER_FOOTER,
|
|
62
63
|
resolveTrialBanner,
|
|
63
64
|
resolvePlanFit,
|
|
65
|
+
planFitOf,
|
|
64
66
|
resolvePeriodComparison,
|
|
67
|
+
periodComparisonOf,
|
|
65
68
|
} from "./lib/homeBlocks";
|
|
66
69
|
export {
|
|
67
70
|
AUTO_PROVISION_TITLE,
|
package/src/lib/creditDisplay.js
CHANGED
|
@@ -98,6 +98,15 @@ function bankBarVariantFor(bankRemaining, bankGranted) {
|
|
|
98
98
|
if (bankRemaining * 100 <= 50 * bankGranted) return "warning";
|
|
99
99
|
return "success";
|
|
100
100
|
}
|
|
101
|
+
// The credits block lives at payload.state.credits on base-hosted backends; a
|
|
102
|
+
// self-hosted backend MAY emit it top-level. Dual-read (nested wins), same as
|
|
103
|
+
// featureUsageOf/planFitOf — without this the meter falls back to the legacy
|
|
104
|
+
// single-bar path (no monthly/additional split, no "renews on" line).
|
|
105
|
+
export function creditsBlockOf(state) {
|
|
106
|
+
if (!state || typeof state !== "object") return null;
|
|
107
|
+
return state.state?.credits ?? state.credits ?? null;
|
|
108
|
+
}
|
|
109
|
+
|
|
101
110
|
export function resolveCreditMeter(entitlement, creditMeter, credits = null) {
|
|
102
111
|
const ent = entitlement?.mode === "credits" ? entitlement : null;
|
|
103
112
|
const meter = creditMeter ?? null;
|
package/src/lib/homeBlocks.js
CHANGED
|
@@ -114,6 +114,15 @@ export function resolvePlanFit(planFit) {
|
|
|
114
114
|
return null;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
// The plan_fit block lives at payload.state.plan_fit on base-hosted backends;
|
|
118
|
+
// a self-hosted backend MAY emit it top-level instead. Dual-read (nested
|
|
119
|
+
// wins), same as featureUsageOf — without this the banner/hero line silently
|
|
120
|
+
// never render (shipped dead 2026-10-12, found 2026-10-13).
|
|
121
|
+
export function planFitOf(state) {
|
|
122
|
+
if (!state || typeof state !== "object") return null;
|
|
123
|
+
return resolvePlanFit(state.state?.plan_fit ?? state.plan_fit);
|
|
124
|
+
}
|
|
125
|
+
|
|
117
126
|
// --- Period comparison ------------------------------------------------------
|
|
118
127
|
|
|
119
128
|
// Resolve the period_comparison block (null until the install has one full
|
|
@@ -144,3 +153,12 @@ export function resolvePeriodComparison(periodComparison) {
|
|
|
144
153
|
maxTotal: Math.max(last.total, current.total, 1),
|
|
145
154
|
};
|
|
146
155
|
}
|
|
156
|
+
|
|
157
|
+
// Same nested-vs-top-level duality as planFitOf: base serves
|
|
158
|
+
// payload.state.period_comparison; self-hosted backends MAY go top-level.
|
|
159
|
+
export function periodComparisonOf(state) {
|
|
160
|
+
if (!state || typeof state !== "object") return null;
|
|
161
|
+
return resolvePeriodComparison(
|
|
162
|
+
state.state?.period_comparison ?? state.period_comparison
|
|
163
|
+
);
|
|
164
|
+
}
|
package/src/usage/UsageTab.jsx
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from "@hubspot/ui-extensions";
|
|
28
28
|
|
|
29
29
|
import { useStrictModeEffect } from "../lib/useStrictModeEffect";
|
|
30
|
+
import { creditsBlockOf } from "../lib/creditDisplay";
|
|
30
31
|
import { CreditMeter } from "../home/CreditMeter";
|
|
31
32
|
|
|
32
33
|
const DEFAULT_BASE_PATH = "/api/v1/usage";
|
|
@@ -56,10 +57,13 @@ export function UsageTab({
|
|
|
56
57
|
return (
|
|
57
58
|
<Flex direction="column" gap="medium">
|
|
58
59
|
{state && (
|
|
60
|
+
// creditsBlockOf dual-reads payload.state.credits (base) ??
|
|
61
|
+
// payload.credits (self-hosted) — a top-level-only read silently
|
|
62
|
+
// dropped the two-pool split + "renews on" line on base-hosted apps.
|
|
59
63
|
<CreditMeter
|
|
60
64
|
entitlement={state.entitlement}
|
|
61
65
|
creditMeter={state.credit_meter}
|
|
62
|
-
credits={state
|
|
66
|
+
credits={creditsBlockOf(state)}
|
|
63
67
|
/>
|
|
64
68
|
)}
|
|
65
69
|
|