Skip to content

Commit 3f02783

Browse files
committed
[dashboard] Prevent upgrading to Chargebee once Usage-Based Pricing is enabled
1 parent a96cb7b commit 3f02783

File tree

2 files changed

+86
-114
lines changed

2 files changed

+86
-114
lines changed

components/dashboard/src/settings/Plans.tsx

Lines changed: 78 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ export default function () {
356356
};
357357

358358
const planCards = [];
359+
const canUpgradeToChargebee = userBillingMode && userBillingMode.mode === "chargebee";
359360

360361
// Plan card: Free a.k.a. Open Source (or Professional Open Source)
361362
const openSourceFeatures = (
@@ -374,7 +375,7 @@ export default function () {
374375
if (currentPlan.chargebeeId === freePlan.chargebeeId) {
375376
planCards.push(
376377
<PlanCard
377-
isDisabled={!!assignedTs || pendingChargebeeCallback}
378+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
378379
plan={freePlan}
379380
isCurrent={!!accountStatement}
380381
>
@@ -409,7 +410,7 @@ export default function () {
409410
}
410411
planCards.push(
411412
<PlanCard
412-
isDisabled={!!assignedTs || pendingChargebeeCallback}
413+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
413414
plan={targetPlan}
414415
isCurrent={false}
415416
onDowngrade={onDowngrade}
@@ -435,7 +436,7 @@ export default function () {
435436
) : undefined;
436437
planCards.push(
437438
<PlanCard
438-
isDisabled={!!assignedTs || pendingChargebeeCallback}
439+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
439440
plan={applyCoupons(personalPlan, appliedCoupons)}
440441
isCurrent={true}
441442
bottomLabel={bottomLabel}
@@ -474,7 +475,7 @@ export default function () {
474475
}
475476
planCards.push(
476477
<PlanCard
477-
isDisabled={!!assignedTs || pendingChargebeeCallback}
478+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
478479
plan={targetPlan}
479480
isCurrent={false}
480481
onUpgrade={onUpgrade}
@@ -505,7 +506,7 @@ export default function () {
505506
) : undefined;
506507
planCards.push(
507508
<PlanCard
508-
isDisabled={!!assignedTs || pendingChargebeeCallback}
509+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
509510
plan={applyCoupons(professionalPlan, appliedCoupons)}
510511
isCurrent={true}
511512
bottomLabel={bottomLabel}
@@ -545,7 +546,7 @@ export default function () {
545546
}
546547
planCards.push(
547548
<PlanCard
548-
isDisabled={!!assignedTs || pendingChargebeeCallback}
549+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
549550
plan={targetPlan}
550551
isCurrent={!!assignedProfessionalTs}
551552
onUpgrade={onUpgrade}
@@ -583,7 +584,7 @@ export default function () {
583584
) : undefined;
584585
planCards.push(
585586
<PlanCard
586-
isDisabled={!!assignedTs || pendingChargebeeCallback}
587+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
587588
plan={applyCoupons(studentUnleashedPlan, appliedCoupons)}
588589
isCurrent={true}
589590
bottomLabel={bottomLabel}
@@ -599,7 +600,7 @@ export default function () {
599600
) : undefined;
600601
planCards.push(
601602
<PlanCard
602-
isDisabled={!!assignedTs || pendingChargebeeCallback}
603+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
603604
plan={applyCoupons(unleashedPlan, appliedCoupons)}
604605
isCurrent={true}
605606
bottomLabel={bottomLabel}
@@ -618,7 +619,7 @@ export default function () {
618619
}
619620
planCards.push(
620621
<PlanCard
621-
isDisabled={!!assignedTs || pendingChargebeeCallback}
622+
isDisabled={!canUpgradeToChargebee || !!assignedTs || pendingChargebeeCallback}
622623
plan={targetPlan}
623624
isCurrent={!!isUnleashedTsAssigned}
624625
onUpgrade={onUpgrade}
@@ -629,101 +630,87 @@ export default function () {
629630
);
630631
}
631632

632-
const showPlans = userBillingMode && userBillingMode.mode === "chargebee";
633633
return (
634634
<div>
635635
<PageWithSettingsSubMenu title="Plans" subtitle="Manage account usage and billing.">
636-
{showPlans && (
637-
<div className="w-full text-center">
638-
<p className="text-xl text-gray-500">
639-
You are currently using the{" "}
640-
<span className="font-bold">
641-
{Plans.getById(assignedTs?.planId)?.name || currentPlan.name}
642-
</span>{" "}
643-
plan.
636+
<div className="w-full text-center">
637+
<p className="text-xl text-gray-500">
638+
You are currently using the{" "}
639+
<span className="font-bold">{Plans.getById(assignedTs?.planId)?.name || currentPlan.name}</span>{" "}
640+
plan.
641+
</p>
642+
{canUpgradeToChargebee && !assignedTs && (
643+
<p className="text-base w-96 m-auto">
644+
Upgrade your plan to get more hours and more parallel workspaces.
644645
</p>
645-
{!assignedTs && (
646-
<p className="text-base w-96 m-auto">
647-
Upgrade your plan to get more hours and more parallel workspaces.
648-
</p>
649-
)}
650-
<Tooltip
651-
content={`Current billing cycle: ${guessCurrentBillingCycle(currentPlan, accountStatement)
652-
.map((d) => d.toLocaleDateString())
653-
.join(" - ")}`}
646+
)}
647+
<Tooltip
648+
content={`Current billing cycle: ${guessCurrentBillingCycle(currentPlan, accountStatement)
649+
.map((d) => d.toLocaleDateString())
650+
.join(" - ")}`}
651+
>
652+
<p className="mt-2 font-semibold text-gray-500">
653+
Remaining hours:{" "}
654+
{typeof accountStatement?.remainingHours === "number"
655+
? Math.floor(accountStatement.remainingHours * 10) / 10
656+
: accountStatement?.remainingHours}
657+
</p>
658+
</Tooltip>
659+
{typeof accountStatement?.remainingHours === "number" &&
660+
typeof currentPlan.hoursPerMonth === "number" ? (
661+
<progress
662+
value={currentPlan.hoursPerMonth - accountStatement.remainingHours}
663+
max={currentPlan.hoursPerMonth}
664+
/>
665+
) : (
666+
<progress value="0" max="100" />
667+
)}
668+
<p className="text-sm">
669+
<a
670+
className={`gp-link ${isChargebeeCustomer ? "" : "invisible"}`}
671+
href="javascript:void(0)"
672+
onClick={() => {
673+
ChargebeeClient.getOrCreate().then((chargebeeClient) => chargebeeClient.openPortal());
674+
}}
654675
>
655-
<p className="mt-2 font-semibold text-gray-500">
656-
Remaining hours:{" "}
657-
{typeof accountStatement?.remainingHours === "number"
658-
? Math.floor(accountStatement.remainingHours * 10) / 10
659-
: accountStatement?.remainingHours}
660-
</p>
661-
</Tooltip>
662-
{typeof accountStatement?.remainingHours === "number" &&
663-
typeof currentPlan.hoursPerMonth === "number" ? (
664-
<progress
665-
value={currentPlan.hoursPerMonth - accountStatement.remainingHours}
666-
max={currentPlan.hoursPerMonth}
667-
/>
668-
) : (
669-
<progress value="0" max="100" />
676+
Billing
677+
</a>
678+
{!!accountStatement && Plans.isFreePlan(currentPlan.chargebeeId) && (
679+
<span className="pl-6">
680+
{currency === "EUR" ? (
681+
<>
682+
€ /{" "}
683+
<a
684+
className="text-blue-light hover:underline"
685+
href="javascript:void(0)"
686+
onClick={() => setCurrency("USD")}
687+
>
688+
$
689+
</a>
690+
</>
691+
) : (
692+
<>
693+
<a
694+
className="text-blue-light hover:underline"
695+
href="javascript:void(0)"
696+
onClick={() => setCurrency("EUR")}
697+
>
698+
699+
</a>{" "}
700+
/ $
701+
</>
702+
)}
703+
</span>
670704
)}
671-
<p className="text-sm">
672-
<a
673-
className={`gp-link ${isChargebeeCustomer ? "" : "invisible"}`}
674-
href="javascript:void(0)"
675-
onClick={() => {
676-
ChargebeeClient.getOrCreate().then((chargebeeClient) =>
677-
chargebeeClient.openPortal(),
678-
);
679-
}}
680-
>
681-
Billing
682-
</a>
683-
{!!accountStatement && Plans.isFreePlan(currentPlan.chargebeeId) && (
684-
<span className="pl-6">
685-
{currency === "EUR" ? (
686-
<>
687-
€ /{" "}
688-
<a
689-
className="text-blue-light hover:underline"
690-
href="javascript:void(0)"
691-
onClick={() => setCurrency("USD")}
692-
>
693-
$
694-
</a>
695-
</>
696-
) : (
697-
<>
698-
<a
699-
className="text-blue-light hover:underline"
700-
href="javascript:void(0)"
701-
onClick={() => setCurrency("EUR")}
702-
>
703-
704-
</a>{" "}
705-
/ $
706-
</>
707-
)}
708-
</span>
709-
)}
710-
</p>
711-
</div>
712-
)}
705+
</p>
706+
</div>
713707
<div className="mt-4 flex justify-center space-x-3 2xl:space-x-7">{planCards}</div>
714708
{assignedTs && userBillingMode?.mode === "chargebee" && !!userBillingMode.teamNames && (
715709
<Alert type="info" className="mt-10 mx-auto">
716710
<p>Assigned Team Seats</p>
717711
<ul>{userBillingMode.teamNames.join(", ")}</ul>
718712
</Alert>
719713
)}
720-
<InfoBox className="w-2/3 mt-14 mx-auto">
721-
If you are interested in purchasing a plan for a team, purchase a Team plan with one centralized
722-
billing.{" "}
723-
<a className="underline" href="https://www.gitpod.io/docs/teams/">
724-
Learn more
725-
</a>
726-
</InfoBox>
727714
{!!confirmUpgradeToPlan && (
728715
// TODO: Use title and buttons props
729716
<Modal visible={true} onClose={() => setConfirmUpgradeToPlan(undefined)}>

components/dashboard/src/settings/Teams.tsx

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* See License-AGPL.txt in the project root for license information.
55
*/
66

7-
import React, { useContext, useEffect, useRef, useState } from "react";
7+
import { useContext, useEffect, useRef, useState } from "react";
88
import ContextMenu, { ContextMenuEntry } from "../components/ContextMenu";
99
import { getGitpodService } from "../service/service";
1010
import Alert from "../components/Alert";
@@ -24,7 +24,6 @@ import { Disposable } from "@gitpod/gitpod-protocol";
2424
import { PaymentContext } from "../payment-context";
2525
import { PageWithSettingsSubMenu } from "./PageWithSettingsSubMenu";
2626
import { UserContext } from "../user-context";
27-
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
2827

2928
export default function Teams() {
3029
return (
@@ -453,8 +452,9 @@ function AllTeams() {
453452
return pendingSlotsPurchase && pendingSlotsPurchase.tsId === ts.id;
454453
};
455454

456-
const renderTeams = () => (
457-
<React.Fragment>
455+
const canUpgradeToChargebee = userBillingMode && userBillingMode.mode === "chargebee";
456+
return (
457+
<div>
458458
<div className="flex flex-row">
459459
<div className="flex-grow ">
460460
<h3 className="self-center">All Team Plans</h3>
@@ -469,7 +469,9 @@ function AllTeams() {
469469
{getActiveSubs().length > 0 && (
470470
<button
471471
className="self-end my-auto"
472-
disabled={!!pendingPlanPurchase || getAvailableSubTypes().length === 0}
472+
disabled={
473+
!canUpgradeToChargebee || !!pendingPlanPurchase || getAvailableSubTypes().length === 0
474+
}
473475
onClick={() => showCreateTeamModal()}
474476
>
475477
Create Team Plan
@@ -501,7 +503,7 @@ function AllTeams() {
501503
<AddMembersModal onClose={() => setAddMembersModal(undefined)} onBuy={onBuy} {...addMembersModal} />
502504
)}
503505

504-
{getActiveSubs().length === 0 && !pendingPlanPurchase && (
506+
{getActiveSubs().length === 0 && !pendingPlanPurchase && canUpgradeToChargebee && (
505507
<div className="w-full flex h-80 mt-2 rounded-xl bg-gray-100 dark:bg-gray-900">
506508
<div className="m-auto text-center">
507509
<h3 className="self-center text-gray-500 dark:text-gray-400 mb-4">No Active Team Plans</h3>
@@ -602,23 +604,6 @@ function AllTeams() {
602604
))}
603605
</div>
604606
)}
605-
</React.Fragment>
606-
);
607-
608-
// TOOD(gpl) We might want to reduce visibility of those actions similarly to how we guard access to that API, cmp.: https://github.com/gitpod-io/gitpod/blob/db90aefb9f7dc1d062e9cb73241c1fda2eccee4b/components/server/ee/src/workspace/gitpod-server-impl.ts#L2011
609-
const showTeamPlans = BillingMode.showTeamSubscriptionUI(userBillingMode);
610-
return (
611-
<div>
612-
{showTeamPlans ? (
613-
renderTeams()
614-
) : (
615-
<div className="flex flex-row">
616-
<div className="flex-grow ">
617-
<h3 className="self-center">All Team Plans</h3>
618-
<h2>Manage team plans and team members.</h2>
619-
</div>
620-
</div>
621-
)}
622607
</div>
623608
);
624609
}

0 commit comments

Comments
 (0)