Skip to content

Commit af658c9

Browse files
authored
Enterprise plans should not have the upgrade button (#7628)
* Enterprise plans should not have the upgrade button Fixes #7627 * Move the check to BillingDialog * Hide home box and change bool check * Add component tests * Clean up
1 parent 7ec11d2 commit af658c9

File tree

3 files changed

+130
-62
lines changed

3 files changed

+130
-62
lines changed

jest-component-unit-tests/billing.jesttest.tsx

Lines changed: 107 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,57 @@ test('Shows a loading spinner when uninitialized credit count', async () => {
125125
await expect(queryByTestId('spinner')).toBeVisible()
126126
})
127127

128-
test('Shows the total credits for Unknown subscription', async () => {
129-
const data = {
130-
balance: {
131-
monthlyApiCreditsRemaining: 10,
132-
stableApiCreditsRemaining: 25,
133-
},
134-
subscriptions: {
135-
monthlyPayAsYouGoApiCreditsTotal: 20,
136-
name: "unknown",
137-
}
128+
const unKnownTierData = {
129+
balance: {
130+
monthlyApiCreditsRemaining: 10,
131+
stableApiCreditsRemaining: 25,
132+
},
133+
subscriptions: {
134+
monthlyPayAsYouGoApiCreditsTotal: 20,
135+
name: "unknown",
136+
}
137+
}
138+
139+
const freeTierData = {
140+
balance: {
141+
monthlyApiCreditsRemaining: 10,
142+
stableApiCreditsRemaining: 0,
143+
},
144+
subscriptions: {
145+
monthlyPayAsYouGoApiCreditsTotal: 20,
146+
name: "free",
147+
}
148+
}
149+
150+
const proTierData = {
151+
// These are all ignored
152+
balance: {
153+
monthlyApiCreditsRemaining: 10,
154+
stableApiCreditsRemaining: 0,
155+
},
156+
subscriptions: {
157+
// This should be ignored because it's Pro tier.
158+
monthlyPayAsYouGoApiCreditsTotal: 20,
159+
name: "pro",
138160
}
161+
}
139162

163+
const enterpriseTierData = {
164+
// These are all ignored, user is part of an org.
165+
balance: {
166+
monthlyApiCreditsRemaining: 10,
167+
stableApiCreditsRemaining: 0,
168+
},
169+
subscriptions: {
170+
// This should be ignored because it's Pro tier.
171+
monthlyPayAsYouGoApiCreditsTotal: 20,
172+
// This should be ignored because the user is part of an Org.
173+
name: "free",
174+
}
175+
}
176+
177+
test('Shows the total credits for Unknown subscription', async () => {
178+
const data = unKnownTierData
140179
server.use(
141180
http.get('*/user/payment/balance', (req, res, ctx) => {
142181
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
@@ -166,17 +205,7 @@ test('Shows the total credits for Unknown subscription', async () => {
166205
})
167206

168207
test('Progress bar reflects ratio left of Free subscription', async () => {
169-
const data = {
170-
balance: {
171-
monthlyApiCreditsRemaining: 10,
172-
stableApiCreditsRemaining: 0,
173-
},
174-
subscriptions: {
175-
monthlyPayAsYouGoApiCreditsTotal: 20,
176-
name: "free",
177-
}
178-
}
179-
208+
const data = freeTierData
180209
server.use(
181210
http.get('*/user/payment/balance', (req, res, ctx) => {
182211
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
@@ -212,19 +241,7 @@ test('Progress bar reflects ratio left of Free subscription', async () => {
212241
})
213242
})
214243
test('Shows infinite credits for Pro subscription', async () => {
215-
const data = {
216-
// These are all ignored
217-
balance: {
218-
monthlyApiCreditsRemaining: 10,
219-
stableApiCreditsRemaining: 0,
220-
},
221-
subscriptions: {
222-
// This should be ignored because it's Pro tier.
223-
monthlyPayAsYouGoApiCreditsTotal: 20,
224-
name: "pro",
225-
}
226-
}
227-
244+
const data = proTierData
228245
server.use(
229246
http.get('*/user/payment/balance', (req, res, ctx) => {
230247
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
@@ -255,19 +272,7 @@ test('Shows infinite credits for Pro subscription', async () => {
255272
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(null)
256273
})
257274
test('Shows infinite credits for Enterprise subscription', async () => {
258-
const data = {
259-
// These are all ignored, user is part of an org.
260-
balance: {
261-
monthlyApiCreditsRemaining: 10,
262-
stableApiCreditsRemaining: 0,
263-
},
264-
subscriptions: {
265-
// This should be ignored because it's Pro tier.
266-
monthlyPayAsYouGoApiCreditsTotal: 20,
267-
// This should be ignored because the user is part of an Org.
268-
name: "free",
269-
}
270-
}
275+
const data = enterpriseTierData
271276

272277
server.use(
273278
http.get('*/user/payment/balance', (req, res, ctx) => {
@@ -297,3 +302,58 @@ test('Shows infinite credits for Enterprise subscription', async () => {
297302
await expect(queryByTestId('infinity')).toBeVisible()
298303
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(null)
299304
})
305+
306+
test('Show upgrade button if credits are not infinite', async () => {
307+
const data = freeTierData
308+
server.use(
309+
http.get('*/user/payment/balance', (req, res, ctx) => {
310+
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
311+
}),
312+
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
313+
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
314+
}),
315+
http.get('*/org', (req, res, ctx) => {
316+
return new HttpResponse(403)
317+
}),
318+
)
319+
320+
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
321+
322+
const { queryByTestId } = render(<BillingDialog
323+
billingActor={billingActor}
324+
/>)
325+
326+
await act(() => {
327+
billingActor.send({ type: BillingTransition.Update, apiToken: "it doesn't matter wtf this is :)" })
328+
})
329+
330+
await expect(queryByTestId('billing-upgrade-button')).toBeVisible()
331+
})
332+
333+
test('Hide upgrade button if credits are infinite', async () => {
334+
const data = enterpriseTierData
335+
server.use(
336+
http.get('*/user/payment/balance', (req, res, ctx) => {
337+
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
338+
}),
339+
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
340+
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
341+
}),
342+
// Ok finally the first use of an org lol
343+
http.get('*/org', (req, res, ctx) => {
344+
return HttpResponse.json(createOrgResponse())
345+
}),
346+
)
347+
348+
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
349+
350+
const { queryByTestId } = render(<BillingDialog
351+
billingActor={billingActor}
352+
/>)
353+
354+
await act(() => {
355+
billingActor.send({ type: BillingTransition.Update, apiToken: "it doesn't matter wtf this is :)" })
356+
})
357+
358+
await expect(queryByTestId('billing-upgrade-button')).toBe(null)
359+
})

src/components/BillingDialog.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
BillingRemainingMode,
77
} from '@src/components/BillingRemaining'
88

9-
import type { BillingActor } from '@src/machines/billingMachine'
9+
import { type BillingActor } from '@src/machines/billingMachine'
1010

1111
export const BillingDialog = (props: { billingActor: BillingActor }) => {
1212
const billingContext = useSelector(
@@ -39,15 +39,18 @@ export const BillingDialog = (props: { billingActor: BillingActor }) => {
3939
mode={BillingRemainingMode.ProgressBarStretch}
4040
billingActor={props.billingActor}
4141
/>
42-
<a
43-
className="bg-ml-black text-ml-white rounded-lg text-center p-1 cursor-pointer"
44-
href="https://zoo.dev/design-studio-pricing"
45-
target="_blank"
46-
rel="noopener noreferrer"
47-
onClick={openExternalBrowserIfDesktop()}
48-
>
49-
Upgrade
50-
</a>
42+
{!hasUnlimited && (
43+
<a
44+
className="bg-ml-black text-ml-white rounded-lg text-center p-1 cursor-pointer"
45+
href="https://zoo.dev/design-studio-pricing"
46+
target="_blank"
47+
rel="noopener noreferrer"
48+
data-testid="billing-upgrade-button"
49+
onClick={openExternalBrowserIfDesktop()}
50+
>
51+
Upgrade
52+
</a>
53+
)}
5154
</div>
5255
</div>
5356
)

src/routes/Home.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import {
6666
defaultLocalStatusBarItems,
6767
defaultGlobalStatusBarItems,
6868
} from '@src/components/StatusBar/defaultStatusBarItems'
69+
import { useSelector } from '@xstate/react'
6970

7071
type ReadWriteProjectState = {
7172
value: boolean
@@ -81,6 +82,8 @@ const Home = () => {
8182
const [nativeFileMenuCreated, setNativeFileMenuCreated] = useState(false)
8283
const apiToken = useToken()
8384
const networkMachineStatus = useNetworkMachineStatus()
85+
const billingContext = useSelector(billingActor, ({ context }) => context)
86+
const hasUnlimitedCredits = billingContext.credits === Infinity
8487

8588
// Only create the native file menus on desktop
8689
useEffect(() => {
@@ -354,11 +357,13 @@ const Home = () => {
354357
</li>
355358
</ul>
356359
<ul className="flex flex-col">
357-
<li className="contents">
358-
<div className="my-2">
359-
<BillingDialog billingActor={billingActor} />
360-
</div>
361-
</li>
360+
{!hasUnlimitedCredits && (
361+
<li className="contents">
362+
<div className="my-2">
363+
<BillingDialog billingActor={billingActor} />
364+
</div>
365+
</li>
366+
)}
362367
<li className="contents">
363368
<ActionButton
364369
Element="externalLink"

0 commit comments

Comments
 (0)