diff --git a/components/dashboard/src/components/ContextMenu.tsx b/components/dashboard/src/components/ContextMenu.tsx index 7b4db1518ef80e..206e8368052713 100644 --- a/components/dashboard/src/components/ContextMenu.tsx +++ b/components/dashboard/src/components/ContextMenu.tsx @@ -35,7 +35,7 @@ function ContextMenu(props: ContextMenuProps) { setExpanded(!expanded); }; - const handler = (evt: KeyboardEvent) => { + const keydownHandler = (evt: KeyboardEvent) => { if (evt.key === "Escape") { setExpanded(false); } @@ -55,11 +55,11 @@ function ContextMenu(props: ContextMenuProps) { }; useEffect(() => { - window.addEventListener("keydown", handler); + window.addEventListener("keydown", keydownHandler); window.addEventListener("click", clickHandler); // Remove event listeners on cleanup return () => { - window.removeEventListener("keydown", handler); + window.removeEventListener("keydown", keydownHandler); window.removeEventListener("click", clickHandler); }; }, []); // Empty array ensures that effect is only run on mount and unmount diff --git a/components/dashboard/src/components/Modal.tsx b/components/dashboard/src/components/Modal.tsx index df1a4e65d06072..c65e7bcbd039fe 100644 --- a/components/dashboard/src/components/Modal.tsx +++ b/components/dashboard/src/components/Modal.tsx @@ -79,7 +79,6 @@ export default function Modal(props: { "relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-xl p-6 max-w-lg mx-auto text-left " + (props.className || "") } - onClick={(e) => e.stopPropagation()} > {props.closeable !== false && (
(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(); @@ -297,7 +299,12 @@ function BillingSetupModal(props: { onClose: () => void }) { return (

Upgrade Billing

-
+
+ {(!stripePromise || !stripeSetupIntentClientSecret) && ( +
+ +
+ )} {!!stripePromise && !!stripeSetupIntentClientSecret && ( void }) { clientSecret: stripeSetupIntentClientSecret, }} > - + )}
@@ -314,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) => { @@ -326,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: { @@ -351,7 +361,25 @@ function CreditCardInputForm() { return (
-
+
+
+ Currency: + setCurrency("EUR"), + }, + { + title: "USD", + onClick: () => setCurrency("USD"), + }, + ]} + /> +