@growth-operations/ui-shared 1.31.1 → 1.32.0

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.31.1",
3
+ "version": "1.32.0",
4
4
  "description": "Shared HubSpot UI-extension modules (Home, Billing) for Growth Operations apps.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -321,12 +321,16 @@ export function TrialSubscriptionBilling({ context, state, appKey, openIframe =
321
321
  : null;
322
322
 
323
323
  // Tier picker — every status needs ONE of two distinct modes, never both:
324
- // trialing -> UPGRADE mode: a trialing sub already
324
+ // trialing / active -> UPGRADE mode: a subscription already
325
325
  // exists, so a higher-tier click swaps its item in place
326
326
  // (/v1/billing/upgrade/start) rather than starting a second
327
327
  // subscription. Lower tiers show disabled (Talk-to-sales; downgrades
328
328
  // aren't self-serve). currentOrder is REQUIRED here so PlanCard can
329
- // tell upgrade from downgrade.
329
+ // tell upgrade from downgrade — and it's a money-safety gate, not
330
+ // caution: the billing service's direction check no-ops when the
331
+ // account's plan matches no mirrored tier, so without a stamped
332
+ // current tier we can't tell a customer what an upgrade even is, and
333
+ // the picker stays hidden (the Stripe portal link above still works).
330
334
  // pending_purchase / canceled -> CHECKOUT mode: there is NO active
331
335
  // subscription to swap — every tier is a genuinely fresh purchase
332
336
  // (/v1/billing/checkout/start, PlanGrid's default). currentOrder is
@@ -336,17 +340,19 @@ export function TrialSubscriptionBilling({ context, state, appKey, openIframe =
336
340
  // (upgrade) or doesn't (checkout) — showing the upgrade endpoint with no
337
341
  // real subscription behind it would 404/error at click time.
338
342
  const isTrialing = ent.status === "trialing";
343
+ const isActive = ent.status === "active";
339
344
  const isCanceled = ent.status === "canceled";
340
345
  const needsCheckout = ent.status === "pending_purchase" || isCanceled;
341
346
  const plans = state?.plans ?? [];
342
- const currentOrder = isTrialing
343
- ? plans.find((p) => p.current)?.tier_order
344
- : undefined;
345
- // Trialing: only once we know the current tier (currentOrder drives
347
+ const currentOrder =
348
+ isTrialing || isActive
349
+ ? plans.find((p) => p.current)?.tier_order
350
+ : undefined;
351
+ // Trialing/active: only once we know the current tier (currentOrder drives
346
352
  // upgrade-vs-downgrade per card). Checkout: as soon as there's a catalog
347
353
  // to pick from — there's no "current tier" gate to wait on.
348
354
  const showPicker =
349
- (isTrialing && currentOrder != null && plans.length > 0) ||
355
+ ((isTrialing || isActive) && currentOrder != null && plans.length > 0) ||
350
356
  (needsCheckout && plans.length > 0);
351
357
 
352
358
  // Empty-catalog restart fallback (2026-10-13 sparkfly incident): a catalog
@@ -415,10 +421,11 @@ export function TrialSubscriptionBilling({ context, state, appKey, openIframe =
415
421
  : "Billing is managed in Stripe across all Growth Operations apps. Use the link above to update your plan, payment method, or view invoices."}
416
422
  </Text>
417
423
 
418
- {/* Trialing: current (marked), higher (upgradeable), lower (disabled,
419
- Talk-to-sales) — upgrading swaps the trialing sub onto the higher
420
- tier, keeping the trial end date. pending_purchase/canceled: every
421
- tier plain-actionable (fresh checkout, PlanGrid's default props/
424
+ {/* Trialing/active: current (marked), higher (upgradeable), lower
425
+ (disabled, Talk-to-sales) — upgrading swaps the existing sub onto
426
+ the higher tier (trial end date kept while trialing; prorated
427
+ immediately once active). pending_purchase/canceled: every tier
428
+ plain-actionable (fresh checkout, PlanGrid's default props/
422
429
  endpoint) — no currentOrder means PlanCard never marks a downgrade.
423
430
  The full `plans` list is passed either way; PlanCard decides each
424
431
  card's state from plan.current + currentOrder. */}
@@ -443,7 +450,9 @@ export function TrialSubscriptionBilling({ context, state, appKey, openIframe =
443
450
  ? "Restart charges your card on file and resumes syncing immediately — no checkout page. If the card needs updating, we'll send you to Stripe to finish. You can also switch to a different plan or billing interval."
444
451
  : needsCheckout
445
452
  ? "Choose a plan to start a new subscription and resume syncing your data."
446
- : "Upgrade any time during your trial — your trial end date stays the same, and the new tier applies when it converts. To move to a lower tier, talk to sales."
453
+ : isActive
454
+ ? "Upgrade any time — the new tier applies right away with prorated billing. To move to a lower tier, talk to sales. Use Manage billing in Stripe above to cancel, update your payment method, or view invoices."
455
+ : "Upgrade any time during your trial — your trial end date stays the same, and the new tier applies when it converts. To move to a lower tier, talk to sales."
447
456
  }
448
457
  // Canceled only: the account's last tier is still stamped
449
458
  // `current` (account.plan persists after cancel), so its card