|
24 | 24 | tierOptions?: { value: string; label: string; badge?: string }[]; |
25 | 25 | }; |
26 | 26 |
|
27 | | - // filter, group, and sort plans |
28 | 27 | $: groupedPlans = (() => { |
29 | 28 | const plans = Object.values(page.data.plans.plans) as Plan[]; |
| 29 | + const groups = filterAndGroupPlans(plans); |
| 30 | + return buildPlanGroups(groups); |
| 31 | + })(); |
| 32 | +
|
| 33 | + $: currentPlanInList = Object.values(page.data.plans.plans).some( |
| 34 | + (plan: Plan) => plan.$id === $currentPlan?.$id |
| 35 | + ); |
| 36 | +
|
| 37 | + $: { |
| 38 | + for (const group of groupedPlans) { |
| 39 | + if (group.isGrouped) { |
| 40 | + selectedTiers[group.key] = getDefaultTierForGroup(group); |
| 41 | + } |
| 42 | + } |
| 43 | + } |
| 44 | +
|
| 45 | + function filterAndGroupPlans(plans: Plan[]): Map<string, Plan[]> { |
30 | 46 | const groups = new Map<string, Plan[]>(); |
31 | 47 |
|
32 | | - // Filter and group in one pass |
33 | 48 | for (const plan of plans) { |
34 | 49 | if (plan.$id === BillingPlan.SCALE) continue; |
35 | 50 |
|
|
42 | 57 | } |
43 | 58 | } |
44 | 59 |
|
45 | | - // convert to array and process groups |
| 60 | + return groups; |
| 61 | + } |
| 62 | +
|
| 63 | + function buildPlanGroups(groups: Map<string, Plan[]>): PlanGroup[] { |
46 | 64 | return Array.from(groups.entries()) |
47 | 65 | .map(([key, groupPlans]) => { |
48 | 66 | const isGrouped = groupPlans.length > 1; |
49 | 67 | const group: PlanGroup = { key, plans: groupPlans, isGrouped }; |
50 | 68 |
|
51 | | - // pre-compute tier options for grouped plans |
52 | 69 | if (isGrouped) { |
53 | | - group.tierOptions = groupPlans.map((plan) => ({ |
54 | | - value: plan.$id, |
55 | | - label: getTierLabel(plan), |
56 | | - badge: $organization?.billingPlan === plan.$id ? 'Current' : undefined |
57 | | - })); |
| 70 | + group.tierOptions = buildTierOptions(groupPlans); |
58 | 71 | } |
59 | 72 |
|
60 | 73 | return group; |
61 | 74 | }) |
62 | 75 | .sort((a, b) => (a.plans[0]?.order ?? 0) - (b.plans[0]?.order ?? 0)); |
63 | | - })(); |
| 76 | + } |
64 | 77 |
|
65 | | - $: currentPlanInList = Object.values(page.data.plans.plans).some( |
66 | | - (plan: Plan) => plan.$id === $currentPlan?.$id |
67 | | - ); |
| 78 | + function buildTierOptions(plans: Plan[]): { value: string; label: string; badge?: string }[] { |
| 79 | + return plans.map((plan) => ({ |
| 80 | + value: plan.$id, |
| 81 | + label: getPlanLabel(plan), |
| 82 | + badge: $organization?.billingPlan === plan.$id ? 'Current' : undefined |
| 83 | + })); |
| 84 | + } |
68 | 85 |
|
69 | | - $: { |
70 | | - for (const group of groupedPlans) { |
71 | | - if (group.isGrouped) { |
72 | | - // check if billingPlan is in this group |
73 | | - const selectedGroupPlan = group.plans.find((p) => p.$id === billingPlan); |
74 | | - if (selectedGroupPlan) { |
75 | | - selectedTiers[group.key] = selectedGroupPlan.$id; |
76 | | - } else { |
77 | | - // If billingPlan not in group, check organization's current plan |
78 | | - const orgCurrentPlan = group.plans.find( |
79 | | - (p) => p.$id === $organization?.billingPlan |
80 | | - ); |
81 | | - if (orgCurrentPlan) { |
82 | | - selectedTiers[group.key] = orgCurrentPlan.$id; |
83 | | - } else if (!selectedTiers[group.key]) { |
84 | | - // default to first plan in group |
85 | | - selectedTiers[group.key] = group.plans[0].$id; |
86 | | - } |
87 | | - } |
88 | | - } |
| 86 | + function getDefaultTierForGroup(group: PlanGroup): string { |
| 87 | + // billingPlan if in group, else org's current plan, else first plan |
| 88 | + const selectedGroupPlan = group.plans.find((p) => p.$id === billingPlan); |
| 89 | + if (selectedGroupPlan) { |
| 90 | + return selectedGroupPlan.$id; |
89 | 91 | } |
90 | | - } |
91 | 92 |
|
92 | | - function handleTierChange(group: PlanGroup) { |
93 | | - billingPlan = selectedTiers[group.key] as BillingPlan; |
| 93 | + const orgCurrentPlan = group.plans.find((p) => p.$id === $organization?.billingPlan); |
| 94 | + if (orgCurrentPlan) { |
| 95 | + return orgCurrentPlan.$id; |
| 96 | + } |
| 97 | +
|
| 98 | + return selectedTiers[group.key] || group.plans[0].$id; |
94 | 99 | } |
95 | 100 |
|
96 | | - function message(plan: Plan): string { |
| 101 | + function getPlanLabel(plan: Plan): string { |
97 | 102 | const price = formatCurrency(plan?.price ?? 0); |
98 | 103 | if (resolvedProfile.id === ProfileMode.STUDIO) { |
99 | 104 | if (plan.limits?.dailyCredits) { |
|
105 | 110 | return `${price} per month`; |
106 | 111 | } |
107 | 112 |
|
108 | | - function getTierLabel(plan: Plan): string { |
109 | | - const price = formatCurrency(plan?.price ?? 0); |
110 | | - if (resolvedProfile.id === ProfileMode.STUDIO) { |
111 | | - if (plan.limits?.dailyCredits) { |
112 | | - return `${plan.limits.dailyCredits.toLocaleString()} daily credits for ${price} per month`; |
113 | | - } else if (plan.limits?.credits) { |
114 | | - return `${plan.limits.credits.toLocaleString()} credits per month for ${price}`; |
115 | | - } |
116 | | - } |
117 | | - return `${price} per month`; |
| 113 | + function handleTierChange(group: PlanGroup) { |
| 114 | + billingPlan = selectedTiers[group.key] as BillingPlan; |
118 | 115 | } |
119 | 116 | </script> |
120 | 117 |
|
|
145 | 142 | {@const isZeroPrice = (basePlan.price ?? 0) <= 0} |
146 | 143 | {@const price = formatCurrency(basePlan.price ?? 0)} |
147 | 144 | {#if resolvedProfile.id === ProfileMode.STUDIO} |
148 | | - {message(basePlan)} |
| 145 | + {getPlanLabel(basePlan)} |
149 | 146 | {:else} |
150 | | - {isZeroPrice ? price : message(basePlan)} |
| 147 | + {isZeroPrice ? price : getPlanLabel(basePlan)} |
151 | 148 | {/if} |
152 | 149 | </Typography.Text> |
153 | 150 | {/if} |
|
183 | 180 | <Typography.Text> |
184 | 181 | {@const isZeroPrice = ($currentPlan?.price ?? 0) <= 0} |
185 | 182 | {@const price = formatCurrency($currentPlan?.price ?? 0)} |
186 | | - {isZeroPrice ? price : message($currentPlan)} |
| 183 | + {isZeroPrice ? price : getPlanLabel($currentPlan)} |
187 | 184 | </Typography.Text> |
188 | 185 | </LabelCard> |
189 | 186 | {/if} |
|
0 commit comments