@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 +1 -1
- package/src/billing/BillingTab.jsx +21 -12
package/package.json
CHANGED
|
@@ -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
|
|
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 =
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
|
419
|
-
Talk-to-sales) — upgrading swaps the
|
|
420
|
-
|
|
421
|
-
|
|
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
|
-
:
|
|
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
|