@@ -20,6 +20,8 @@ import DropDown from "../components/DropDown";
20
20
import Modal from "../components/Modal" ;
21
21
import Alert from "./Alert" ;
22
22
23
+ const BASE_USAGE_LIMIT_FOR_STRIPE_USERS = 1000 ;
24
+
23
25
type PendingStripeSubscription = { pendingSince : number } ;
24
26
25
27
interface Props {
@@ -92,13 +94,13 @@ export default function UsageBasedBillingConfig({ attributionId }: Props) {
92
94
setPendingStripeSubscription ( pendingSubscription ) ;
93
95
window . localStorage . setItem ( localStorageKey , JSON . stringify ( pendingSubscription ) ) ;
94
96
try {
95
- // Pick a good initial value for the Stripe usage limit (1000 * team_size)
97
+ // Pick a good initial value for the Stripe usage limit (base_limit * team_size)
96
98
// FIXME: Should we ask the customer to confirm or edit this default limit?
97
- let limit = 1000 ;
99
+ let limit = BASE_USAGE_LIMIT_FOR_STRIPE_USERS ;
98
100
const attrId = AttributionId . parse ( attributionId ) ;
99
101
if ( attrId ?. kind === "team" ) {
100
102
const members = await getGitpodService ( ) . server . getTeamMembers ( attrId . teamId ) ;
101
- limit = 1000 * members . length ;
103
+ limit = BASE_USAGE_LIMIT_FOR_STRIPE_USERS * members . length ;
102
104
}
103
105
await getGitpodService ( ) . server . subscribeToStripe ( attributionId , setupIntentId , limit ) ;
104
106
const newLimit = await getGitpodService ( ) . server . getUsageLimit ( attributionId ) ;
@@ -409,7 +411,11 @@ export default function UsageBasedBillingConfig({ attributionId }: Props) {
409
411
) }
410
412
{ showUpdateLimitModal && (
411
413
< UpdateLimitModal
412
- minValue = { AttributionId . parse ( attributionId || "" ) ?. kind === "user" ? 1000 : 0 }
414
+ minValue = {
415
+ AttributionId . parse ( attributionId || "" ) ?. kind === "user"
416
+ ? BASE_USAGE_LIMIT_FOR_STRIPE_USERS
417
+ : 0
418
+ }
413
419
currentValue = { usageLimit }
414
420
onClose = { ( ) => setShowUpdateLimitModal ( false ) }
415
421
onUpdate = { ( newLimit ) => updateUsageLimit ( newLimit ) }
@@ -545,46 +551,59 @@ function UpdateLimitModal(props: {
545
551
onClose : ( ) => void ;
546
552
onUpdate : ( newLimit : number ) => { } ;
547
553
} ) {
554
+ const [ error , setError ] = useState < string > ( "" ) ;
548
555
const [ newLimit , setNewLimit ] = useState < string | undefined > (
549
556
typeof props . currentValue === "number" ? String ( props . currentValue ) : undefined ,
550
557
) ;
551
558
552
- return (
553
- < Modal visible = { true } onClose = { props . onClose } >
554
- < h3 className = "flex" > Usage Limit</ h3 >
555
- < div className = "border-t border-b border-gray-200 dark:border-gray-700 -mx-6 px-6 py-4 flex flex-col" >
556
- < p className = "pb-4 text-gray-500 text-base" > Set usage limit in total credits per month.</ p >
559
+ function onSubmit ( event : React . FormEvent ) {
560
+ event . preventDefault ( ) ;
561
+ if ( ! newLimit ) {
562
+ setError ( "Please specify a limit" ) ;
563
+ return ;
564
+ }
565
+ const n = parseInt ( newLimit , 10 ) ;
566
+ if ( typeof n !== "number" ) {
567
+ setError ( "Please specify a limit that is a valid number" ) ;
568
+ return ;
569
+ }
570
+ if ( typeof props . minValue === "number" && n < props . minValue ) {
571
+ setError ( `Please specify a limit that is >= ${ props . minValue } ` ) ;
572
+ return ;
573
+ }
574
+ props . onUpdate ( n ) ;
575
+ }
557
576
558
- < label className = "font-medium" >
559
- Credits
560
- < div className = "w-full" >
561
- < input
562
- type = "number"
563
- min = { props . minValue || 0 }
564
- value = { newLimit }
565
- className = "rounded-md w-full truncate overflow-x-scroll pr-8"
566
- onChange = { ( e ) => setNewLimit ( e . target . value ) }
567
- / >
568
- </ div >
569
- </ label >
570
- </ div >
571
- < div className = "flex justify-end mt-6 space-x-2 " >
572
- < button
573
- className = "secondary "
574
- onClick = { ( ) => {
575
- if ( ! newLimit ) {
576
- return ;
577
- }
578
- const n = parseInt ( newLimit , 10 ) ;
579
- if ( typeof n !== "number" ) {
580
- return ;
581
- }
582
- props . onUpdate ( n ) ;
583
- } }
584
- >
585
- Update
586
- </ button >
587
- </ div >
577
+ return (
578
+ < Modal visible = { true } onClose = { props . onClose } onEnter = { ( ) => false } >
579
+ < h3 className = "mb-4" > Usage Limit </ h3 >
580
+ < form onSubmit = { onSubmit } >
581
+ < div className = "border-t border-b border-gray-200 dark:border-gray-700 -mx-6 px-6 py-4 flex flex-col" >
582
+ < p className = "pb-4 text-gray-500 text-base" > Set usage limit in total credits per month. </ p >
583
+ { error && (
584
+ < Alert type = "error" className = "-mt-2 mb-2" >
585
+ { error }
586
+ </ Alert >
587
+ ) }
588
+ < label className = "font-medium" >
589
+ Credits
590
+ < div className = "w-full " >
591
+ < input
592
+ type = "text "
593
+ value = { newLimit }
594
+ className = { `rounded-md w-full truncate overflow-x-scroll pr-8 ${ error ? "error" : "" } ` }
595
+ onChange = { ( e ) => {
596
+ setError ( "" ) ;
597
+ setNewLimit ( e . target . value ) ;
598
+ } }
599
+ />
600
+ </ div >
601
+ </ label >
602
+ </ div >
603
+ < div className = "flex justify-end mt-6 space-x-2" >
604
+ < button className = "secondary" > Update</ button >
605
+ </ div >
606
+ </ form >
588
607
</ Modal >
589
608
) ;
590
609
}
0 commit comments