@growth-operations/ui-shared 1.12.4 → 1.13.1

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.12.4",
3
+ "version": "1.13.1",
4
4
  "description": "Shared HubSpot UI-extension modules (Home, Billing) for Growth Operations apps.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -350,13 +350,25 @@ function CreditsBilling({ context, state, appKey, openIframe = null }) {
350
350
  `&return_url=${encodeURIComponent(returnUrl)}`
351
351
  : null;
352
352
 
353
- // PAID: do NOT show the plan picker. The picker's "Choose" starts a NEW Stripe
354
- // Checkout subscription — clicking another tier would create a SECOND
355
- // subscription (double-bill), not switch in place. Plan changes (upgrade/
356
- // downgrade/cancel) go through the Stripe Customer Portal, which swaps the
357
- // subscription item with proration. So on a paid plan we show the meter + a
358
- // "Manage subscription" portal link only. (Matches toast/sparkfly.)
353
+ // PAID: an UPGRADE-ONLY picker, same trial-archetype pattern as
354
+ // TrialSubscriptionBilling above — higher tiers are one-click in-app via
355
+ // /v1/billing/upgrade/start, which swaps the EXISTING subscription's item
356
+ // in place (never a new Checkout session), so a click here can never
357
+ // double-bill. currentOrder (this tier's rank) makes PlanCard mark the
358
+ // current tier and disable everything ranked below it ("Talk to sales to
359
+ // switch") — the backend independently re-validates the same upgrade
360
+ // direction (start_upgrade_redirect's tier_order check), so this is safe
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).
359
368
  if (onPaidPlan) {
369
+ const plans = state?.plans ?? [];
370
+ const currentOrder = plans.find((p) => p.current)?.tier_order;
371
+ const showPicker = currentOrder != null && plans.length > 0;
360
372
  return (
361
373
  <Flex direction="column" gap="medium">
362
374
  <CreditMeter
@@ -372,10 +384,24 @@ function CreditsBilling({ context, state, appKey, openIframe = null }) {
372
384
  >
373
385
  {portalStartUrl ? "Manage subscription" : "Preparing billing…"}
374
386
  </LoadingButton>
375
- <Text format={{ fontStyle: "italic" }}>
376
- Change or cancel your plan in Stripe — billing is managed across all
377
- Growth Operations apps.
378
- </Text>
387
+ {showPicker ? (
388
+ <PlanGrid
389
+ context={context}
390
+ state={state}
391
+ appKey={appKey}
392
+ currentOrder={currentOrder}
393
+ endpoint="upgrade/start"
394
+ ctaLabel="Upgrade to"
395
+ heading="Your plan"
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."
397
+ openIframe={openIframe}
398
+ />
399
+ ) : (
400
+ <Text format={{ fontStyle: "italic" }}>
401
+ Change or cancel your plan in Stripe — billing is managed across all
402
+ Growth Operations apps.
403
+ </Text>
404
+ )}
379
405
  </Flex>
380
406
  );
381
407
  }