@growth-operations/ui-shared 1.12.4 → 1.13.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.12.4",
3
+ "version": "1.13.0",
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,20 @@ 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/cancel/payment method/
362
+ // invoices still go through the Stripe Customer Portal link below.
359
363
  if (onPaidPlan) {
364
+ const plans = state?.plans ?? [];
365
+ const currentOrder = plans.find((p) => p.current)?.tier_order;
366
+ const showPicker = currentOrder != null && plans.length > 0;
360
367
  return (
361
368
  <Flex direction="column" gap="medium">
362
369
  <CreditMeter
@@ -372,10 +379,24 @@ function CreditsBilling({ context, state, appKey, openIframe = null }) {
372
379
  >
373
380
  {portalStartUrl ? "Manage subscription" : "Preparing billing…"}
374
381
  </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>
382
+ {showPicker ? (
383
+ <PlanGrid
384
+ context={context}
385
+ state={state}
386
+ appKey={appKey}
387
+ currentOrder={currentOrder}
388
+ endpoint="upgrade/start"
389
+ ctaLabel="Upgrade to"
390
+ heading="Your plan"
391
+ footnote="Upgrade any time — the new tier applies immediately with prorated billing. To move to a lower tier, cancel, or update your payment method, use Manage subscription above."
392
+ openIframe={openIframe}
393
+ />
394
+ ) : (
395
+ <Text format={{ fontStyle: "italic" }}>
396
+ Change or cancel your plan in Stripe — billing is managed across all
397
+ Growth Operations apps.
398
+ </Text>
399
+ )}
379
400
  </Flex>
380
401
  );
381
402
  }