@nebulr-group/bridge-svelte 0.4.0 → 0.4.2

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.
@@ -91,12 +91,44 @@
91
91
  : (availableIntervals[0] ?? defaultInterval);
92
92
  });
93
93
 
94
- // Prices to show for a plan under the active tab: the matching interval, plus
95
- // any free (amount-0) prices which apply regardless of interval.
94
+ // Prices to show for a plan under the active tab at most ONE, because each
95
+ // price renders its own select button.
96
+ //
97
+ // The previous filter was `p.amount === 0 || p.recurrenceInterval === selected`,
98
+ // where the zero-amount test short-circuited the interval test. A free plan
99
+ // defining both `0/month` and `0/year` therefore matched twice and rendered two
100
+ // identical "Select free plan" buttons — visible on The Bridge's own /plan page,
101
+ // whose free plan ("Startup") carries a zero price per interval.
102
+ //
103
+ // The intent behind that clause was that a free plan stays selectable under
104
+ // every tab, which is preserved below: prefer the active interval's price, and
105
+ // fall back to a free price from any interval so a free-on-yearly-only plan
106
+ // doesn't render as "Not available monthly".
96
107
  function pricesForInterval(plan: Plan): PriceOfferSdk[] {
97
- return plan.prices.filter(
98
- (p) => p.amount === 0 || p.recurrenceInterval === selectedInterval,
99
- );
108
+ const exact = plan.prices.filter((p) => p.recurrenceInterval === selectedInterval);
109
+ if (exact.length > 0) return exact;
110
+
111
+ const free = plan.prices.find((p) => p.amount === 0);
112
+ return free ? [free] : [];
113
+ }
114
+
115
+ // Cheapest first. The API returns plans in catalog insertion order, which on
116
+ // prod is growth → starter → free — putting the free plan last, below the most
117
+ // expensive one.
118
+ //
119
+ // The sort key is each plan's cheapest price across ALL intervals, not the
120
+ // active interval's, so the order stays put when the user toggles
121
+ // Monthly/Yearly. A plan's tier is a property of the plan; cards reshuffling
122
+ // under the cursor on a tab switch is worse than the edge case it would fix
123
+ // (a catalog whose yearly ranking inverts its monthly one). Plans with no
124
+ // price sort last rather than being treated as free.
125
+ const sortedPlans = $derived(
126
+ [...(plans ?? [])].sort((a, b) => minAmount(a) - minAmount(b)),
127
+ );
128
+
129
+ function minAmount(plan: Plan): number {
130
+ const amounts = (plan.prices ?? []).map((p) => p.amount);
131
+ return amounts.length > 0 ? Math.min(...amounts) : Number.POSITIVE_INFINITY;
100
132
  }
101
133
 
102
134
  type UiState = 'idle' | 'payment-failed' | 'setup-payments' | 'select-plan' | 'active' | 'trial';
@@ -292,7 +324,7 @@
292
324
  {/if}
293
325
 
294
326
  <div class="bridge-plan-cards" data-bridge-plan-cards>
295
- {#each plans as plan (plan.key)}
327
+ {#each sortedPlans as plan (plan.key)}
296
328
  {@const isCurrent = plan.key === currentPlanKey}
297
329
  {@const onPick = (price: PriceOfferSdk) => handlePick(plan, price)}
298
330
  {@const visiblePrices = pricesForInterval(plan)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebulr-group/bridge-svelte",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Bridge Svelte library, This library helps you to add bridge authentication and feature flags, and payments to your svelte application.",
5
5
  "author": "Iman Pouya",
6
6
  "license": "MIT",
@@ -64,7 +64,7 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@simplewebauthn/browser": "^13.0.0",
67
- "@nebulr-group/bridge-auth-core": "0.4.0"
67
+ "@nebulr-group/bridge-auth-core": "0.4.1"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@sveltejs/kit": "^2.16.0",