@growth-operations/ui-shared 1.37.3 → 1.37.4

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@growth-operations/ui-shared",
3
- "version": "1.37.3",
3
+ "version": "1.37.4",
4
4
  "description": "Shared HubSpot UI-extension modules (Home, Billing) for Growth Operations apps.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -91,6 +91,13 @@ export function AppHome({ state, onNavigate, appName, onRetry, helpfulLinks, usa
91
91
 
92
92
  const onboardingComplete = state.onboarding?.complete === true;
93
93
 
94
+ // Legacy (Anvil-billed) installs: hide the period chart entirely. The
95
+ // periods-mode usage endpoint returns an EMPTY series for legacy by design
96
+ // (no Anvil stripe_usage reconstruction in usage_periods.py), so the
97
+ // explorer would render a misleading "No usage in this window" while the
98
+ // Usage tab's days mode shows real activity (USLS, 2026-11-12).
99
+ const isLegacy = state.entitlement?.mode === "legacy";
100
+
94
101
  // FeatureUsage gate: render once every NON-BILLING onboarding step is done.
95
102
  // Every registry app marks its Choose-a-plan step paid-gated (key "plan",
96
103
  // routing to /billing, done only once the subscription is ACTIVE), so gating
@@ -137,20 +144,22 @@ export function AppHome({ state, onNavigate, appName, onRetry, helpfulLinks, usa
137
144
  state ("No usage in this window") is the right thing to show there,
138
145
  not nothing. The paid-step trap this gate grew out of (Andrew
139
146
  2026-11-11) is moot once there's no gate. FeatureUsage below keeps
140
- the setupStepsComplete gate. */}
141
- {usageExplorer ? (
142
- <BillingPeriodUsage
143
- context={usageExplorer.context}
144
- basePath={usageExplorer.basePath}
145
- portalId={usageExplorer.portalId}
146
- appName={appName}
147
- title="Usage over time"
148
- titleAs="text"
149
- showStats={false}
150
- />
151
- ) : (
152
- <PeriodComparison state={state} />
153
- )}
147
+ the setupStepsComplete gate. ONE exception: legacy installs skip
148
+ the chart (see isLegacy above). */}
149
+ {!isLegacy &&
150
+ (usageExplorer ? (
151
+ <BillingPeriodUsage
152
+ context={usageExplorer.context}
153
+ basePath={usageExplorer.basePath}
154
+ portalId={usageExplorer.portalId}
155
+ appName={appName}
156
+ title="Usage over time"
157
+ titleAs="text"
158
+ showStats={false}
159
+ />
160
+ ) : (
161
+ <PeriodComparison state={state} />
162
+ ))}
154
163
 
155
164
  {/* Most used / recommended-to-explore (state.feature_usage) — renders
156
165
  nothing on backends without the block or for legacy installs. Gated
@@ -112,6 +112,27 @@ export function HealthHero({ appName, state }) {
112
112
  );
113
113
  }
114
114
 
115
+ // Legacy (Anvil-billed) install — the calm hero matching BillingTab's
116
+ // LegacyBilling panel. MUST come before the status fallback below:
117
+ // "legacy" is not in STATUS_LABELS/STATUS_VARIANT, so it would render the
118
+ // literal word "legacy" as the banner title (USLS portal 4064313,
119
+ // 2026-11-12 — reads like a debug string to a paying customer).
120
+ if (ent.mode === "legacy") {
121
+ return (
122
+ <Flex direction="column" gap="small">
123
+ {name && <Heading>{name}</Heading>}
124
+ <Alert title="Managed through your existing subscription" variant="info">
125
+ <Box flex="auto">
126
+ <Text>
127
+ Your plan and payment method are billed through your existing
128
+ subscription. There's nothing to set up here.
129
+ </Text>
130
+ </Box>
131
+ </Alert>
132
+ </Flex>
133
+ );
134
+ }
135
+
115
136
  // trial_subscription (and any other status-bearing arm).
116
137
  return (
117
138
  <Flex direction="column" gap="small">