From e2381bba745917dca54786cf71c9770ecca04b43 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Tue, 30 Aug 2022 08:12:37 +0000 Subject: [PATCH 1/5] [gitpod-db] Increase "before each" timeout of AccountingDBSpec and AuthProviderEntryDBSpec --- components/gitpod-db/src/accounting-db.spec.db.ts | 1 + components/gitpod-db/src/auth-provider-entry.spec.db.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/components/gitpod-db/src/accounting-db.spec.db.ts b/components/gitpod-db/src/accounting-db.spec.db.ts index 0002a93b93b35a..758ab0d6aaa883 100644 --- a/components/gitpod-db/src/accounting-db.spec.db.ts +++ b/components/gitpod-db/src/accounting-db.spec.db.ts @@ -26,6 +26,7 @@ export class AccountingDBSpec { db: AccountingDB; queryRunner: QueryRunner; + @timeout(10000) async before() { const connection = await this.typeORM.getConnection(); const manager = connection.manager; diff --git a/components/gitpod-db/src/auth-provider-entry.spec.db.ts b/components/gitpod-db/src/auth-provider-entry.spec.db.ts index 86d29f6e390e9d..a1f5d4955d7688 100644 --- a/components/gitpod-db/src/auth-provider-entry.spec.db.ts +++ b/components/gitpod-db/src/auth-provider-entry.spec.db.ts @@ -19,6 +19,7 @@ export class AuthProviderEntryDBSpec { typeORM = testContainer.get(TypeORM); db = testContainer.get(AuthProviderEntryDB); + @timeout(10000) async before() { await this.clear(); } From fded9fc4c608027e2e01ef58f79924257328fbe2 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Mon, 29 Aug 2022 15:11:06 +0000 Subject: [PATCH 2/5] [dashboard] Fix Stripe credit card input modal overflow on error state --- components/dashboard/src/teams/TeamUsageBasedBilling.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/dashboard/src/teams/TeamUsageBasedBilling.tsx b/components/dashboard/src/teams/TeamUsageBasedBilling.tsx index 3d015c3fda52ee..e39002b0a4c584 100644 --- a/components/dashboard/src/teams/TeamUsageBasedBilling.tsx +++ b/components/dashboard/src/teams/TeamUsageBasedBilling.tsx @@ -297,7 +297,12 @@ function BillingSetupModal(props: { onClose: () => void }) { return (

Upgrade Billing

-
+
+ {(!stripePromise || !stripeSetupIntentClientSecret) && ( +
+ +
+ )} {!!stripePromise && !!stripeSetupIntentClientSecret && ( Date: Thu, 25 Aug 2022 10:07:35 +0000 Subject: [PATCH 3/5] [server][dashboard] Allow new Stripe customers to select their preferred billing currency --- .../src/teams/TeamUsageBasedBilling.tsx | 39 +++++++++++++++---- .../gitpod-protocol/src/gitpod-service.ts | 4 +- .../server/ee/src/user/stripe-service.ts | 38 ++++++++---------- .../ee/src/workspace/gitpod-server-impl.ts | 35 ++++++++++++----- components/server/src/auth/rate-limiter.ts | 1 + components/server/src/config.ts | 2 +- .../src/workspace/gitpod-server-impl.ts | 11 ++---- 7 files changed, 81 insertions(+), 49 deletions(-) diff --git a/components/dashboard/src/teams/TeamUsageBasedBilling.tsx b/components/dashboard/src/teams/TeamUsageBasedBilling.tsx index e39002b0a4c584..76d7f1b790917f 100644 --- a/components/dashboard/src/teams/TeamUsageBasedBilling.tsx +++ b/components/dashboard/src/teams/TeamUsageBasedBilling.tsx @@ -6,15 +6,16 @@ import React, { useContext, useEffect, useState } from "react"; import { useLocation } from "react-router"; +import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode"; import { Appearance, loadStripe, Stripe } from "@stripe/stripe-js"; import { Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js"; import { getCurrentTeam, TeamsContext } from "./teams-context"; +import DropDown from "../components/DropDown"; import Modal from "../components/Modal"; import { ReactComponent as Spinner } from "../icons/Spinner.svg"; import { PaymentContext } from "../payment-context"; import { getGitpodService } from "../service/service"; import { ThemeContext } from "../theme-context"; -import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode"; type PendingStripeSubscription = { pendingSince: number }; @@ -22,7 +23,6 @@ export default function TeamUsageBasedBilling() { const { teams } = useContext(TeamsContext); const location = useLocation(); const team = getCurrentTeam(location, teams); - const { currency } = useContext(PaymentContext); const [teamBillingMode, setTeamBillingMode] = useState(undefined); const [stripeSubscriptionId, setStripeSubscriptionId] = useState(); const [isLoading, setIsLoading] = useState(true); @@ -87,7 +87,7 @@ export default function TeamUsageBasedBilling() { JSON.stringify(pendingSubscription), ); try { - await getGitpodService().server.subscribeTeamToStripe(team.id, setupIntentId, currency); + await getGitpodService().server.subscribeTeamToStripe(team.id, setupIntentId); } catch (error) { console.error("Could not subscribe team to Stripe", error); window.localStorage.removeItem(`pendingStripeSubscriptionForTeam${team.id}`); @@ -214,7 +214,9 @@ export default function TeamUsageBasedBilling() {
)}
- {showBillingSetupModal && setShowBillingSetupModal(false)} />} + {showBillingSetupModal && ( + setShowBillingSetupModal(false)} /> + )} {showUpdateLimitModal && ( void }) { +function BillingSetupModal(props: { teamId: string; onClose: () => void }) { const { isDark } = useContext(ThemeContext); const [stripePromise, setStripePromise] = useState | undefined>(); const [stripeSetupIntentClientSecret, setStripeSetupIntentClientSecret] = useState(); @@ -311,7 +313,7 @@ function BillingSetupModal(props: { onClose: () => void }) { clientSecret: stripeSetupIntentClientSecret, }} > - + )} @@ -319,9 +321,10 @@ function BillingSetupModal(props: { onClose: () => void }) { ); } -function CreditCardInputForm() { +function CreditCardInputForm(props: { teamId: string }) { const stripe = useStripe(); const elements = useElements(); + const { currency, setCurrency } = useContext(PaymentContext); const [isLoading, setIsLoading] = useState(false); const handleSubmit = async (event: React.FormEvent) => { @@ -331,6 +334,8 @@ function CreditCardInputForm() { } setIsLoading(true); try { + // Create Stripe customer for team & currency (or update currency) + await getGitpodService().server.createOrUpdateStripeCustomerForTeam(props.teamId, currency); const result = await stripe.confirmSetup({ elements, confirmParams: { @@ -356,7 +361,25 @@ function CreditCardInputForm() { return (
-
+
+
+ Currency: + setCurrency("EUR"), + }, + { + title: "USD", + onClick: () => setCurrency("USD"), + }, + ]} + /> +