@@ -58,30 +58,35 @@ function CreditsChipInner() {
5858 )
5959
6060 /**
61- * A per-member org credit cap is the authoritative personal remaining for this
62- * member — show it even when the plan-based chip would otherwise be hidden (e.g.
63- * external members). Values are dollars (the chip formats via `formatCredits`),
64- * clamped at 0 so an over-cap member never sees a negative.
61+ * Pooled/plan remaining (dollars): unused plan allowance plus any purchased
62+ * credit balance. Null when the plan-based chip wouldn't show on its own (data
63+ * not ready, or the plan isn't credit-metered). `ON_DEMAND_UNLIMITED` means
64+ * effectively unbounded — rendered as ∞ — so short-circuit instead of
65+ * subtracting usage from the sentinel.
6566 */
66- const limitDollars = memberCredits ?. limitDollars ?? null
67- if ( limitDollars !== null ) {
68- return renderChip ( Math . max ( 0 , limitDollars - ( memberCredits ?. usedDollars ?? 0 ) ) )
69- }
70-
71- if ( isLoading || ! hasData || ! data ?. data ) return null
72- if ( ! planView . showCredits ) return null
73-
74- const { usageLimit, currentUsage, creditBalance } = data . data
67+ const pooledData = ! isLoading && hasData && planView . showCredits ? ( data ?. data ?? null ) : null
68+ const pooledRemaining =
69+ pooledData === null
70+ ? null
71+ : pooledData . usageLimit >= ON_DEMAND_UNLIMITED
72+ ? ON_DEMAND_UNLIMITED
73+ : Math . max ( 0 , pooledData . usageLimit + pooledData . creditBalance - pooledData . currentUsage )
7574
7675 /**
77- * Credits remaining = unused plan allowance plus any purchased credit balance.
78- * Uncapped plans (limit at/above the on-demand threshold) render as ∞ via
79- * `formatCredits`, so short-circuit instead of subtracting usage from it.
76+ * A per-member cap is the authoritative personal remaining, but the actor gate
77+ * blocks on the pooled cap first — so show the tighter of the two, or a member
78+ * could see credits left while every action 402s on org/plan usage. Clamp at 0.
79+ * Fall back to personal alone when pooled isn't available/shown, so a capped
80+ * member still sees a balance even where the plan chip would be hidden.
8081 */
81- const remainingCredits =
82- usageLimit >= ON_DEMAND_UNLIMITED
83- ? ON_DEMAND_UNLIMITED
84- : Math . max ( 0 , usageLimit + creditBalance - currentUsage )
82+ const limitDollars = memberCredits ?. limitDollars ?? null
83+ if ( limitDollars !== null ) {
84+ const personalRemaining = Math . max ( 0 , limitDollars - ( memberCredits ?. usedDollars ?? 0 ) )
85+ return renderChip (
86+ pooledRemaining === null ? personalRemaining : Math . min ( personalRemaining , pooledRemaining )
87+ )
88+ }
8589
86- return renderChip ( remainingCredits )
90+ if ( pooledRemaining === null ) return null
91+ return renderChip ( pooledRemaining )
8792}
0 commit comments