@@ -58,6 +58,7 @@ import {
5858 expandSpecifier ,
5959} from "../../util/resource" ;
6060import { clearEmptyObject } from "../../util/misc" ;
61+ import { isLimitedFreePlan } from "../../util/plan" ;
6162import ShowLoading from "../../ShowLoading" ;
6263import ShowError from "../../ShowError" ;
6364import ScreenContent from "../../ScreenContent" ;
@@ -85,6 +86,7 @@ import LabelWithTooltip from "../../LabelWithTooltip";
8586import PhoneInputListWidget from "./PhoneInputListWidget" ;
8687import PasswordSettings from "./PasswordSettings" ;
8788import ShowOnlyIfSIWEIsDisabled from "./ShowOnlyIfSIWEIsDisabled" ;
89+ import BlueMessageBar from "../../BlueMessageBar" ;
8890import { useTagPickerWithNewTags } from "../../hook/useInput" ;
8991import { fixTagPickerStyles } from "../../bugs" ;
9092import { useResourceForm } from "../../hook/useResourceForm" ;
@@ -495,6 +497,7 @@ interface ConfigFormState {
495497}
496498
497499interface FeatureConfigFormState {
500+ planName : string | null ;
498501 phoneLoginIDDisabled : boolean ;
499502 passwordPolicyFeatureConfig : PasswordPolicyFeatureConfig ;
500503}
@@ -517,6 +520,35 @@ interface FormModel {
517520 save : ( ) => Promise < void > ;
518521}
519522
523+ function shouldShowFreePlanWarning ( formState : FormState ) : boolean {
524+ const {
525+ identitiesControl,
526+ loginIDKeyConfigsControl,
527+ primaryAuthenticatorsControl,
528+ planName,
529+ } = formState ;
530+
531+ if ( planName == null ) {
532+ return false ;
533+ }
534+
535+ if ( ! isLimitedFreePlan ( planName ) ) {
536+ return false ;
537+ }
538+
539+ // For our purpose, controlListUnwrap is sufficient here.
540+ const identities = controlListUnwrap ( identitiesControl ) ;
541+ const loginIDKeyConfigs = controlListUnwrap ( loginIDKeyConfigsControl ) ;
542+ const primaryAuthenticators = controlListUnwrap ( primaryAuthenticatorsControl ) ;
543+
544+ const loginIDEnabled = identities . includes ( "login_id" ) ;
545+ const phoneEnabled =
546+ loginIDKeyConfigs . find ( ( a ) => a . type === "phone" ) != null ;
547+ const oobOTPSMSEnabled = primaryAuthenticators . includes ( "oob_otp_sms" ) ;
548+
549+ return loginIDEnabled && phoneEnabled && oobOTPSMSEnabled ;
550+ }
551+
520552// eslint-disable-next-line complexity
521553function loginMethodFromFormState ( formState : FormState ) : LoginMethod {
522554 const {
@@ -1548,6 +1580,7 @@ function AuthenticationButton(props: AuthenticationButtonProps) {
15481580
15491581interface LoginMethodChooserProps {
15501582 loginMethod : LoginMethod ;
1583+ showFreePlanWarning : boolean ;
15511584 phoneLoginIDDisabled : boolean ;
15521585 passkeyChecked : boolean ;
15531586 appID : string ;
@@ -1558,6 +1591,7 @@ interface LoginMethodChooserProps {
15581591function LoginMethodChooser ( props : LoginMethodChooserProps ) {
15591592 const {
15601593 loginMethod,
1594+ showFreePlanWarning,
15611595 phoneLoginIDDisabled,
15621596 appID,
15631597 onChangeLoginMethod,
@@ -1716,6 +1750,11 @@ function LoginMethodChooser(props: LoginMethodChooserProps) {
17161750 onChange = { onChangePasskeyChecked }
17171751 />
17181752 ) }
1753+ { showFreePlanWarning ? (
1754+ < BlueMessageBar >
1755+ < FormattedMessage id = "warnings.free-plan" />
1756+ </ BlueMessageBar >
1757+ ) : null }
17191758 </ Widget >
17201759 ) ;
17211760}
@@ -2905,6 +2944,11 @@ const LoginMethodConfigurationContent: React.VFC<LoginMethodConfigurationContent
29052944 resources,
29062945 } = state ;
29072946
2947+ const showFreePlanWarning = useMemo (
2948+ ( ) => shouldShowFreePlanWarning ( state ) ,
2949+ [ state ]
2950+ ) ;
2951+
29082952 const isPasswordlessEnabled = useMemo ( ( ) => {
29092953 return primaryAuthenticatorsControl
29102954 . filter ( ( c ) => c . value === "oob_otp_email" || c . value === "oob_otp_sms" )
@@ -3059,6 +3103,7 @@ const LoginMethodConfigurationContent: React.VFC<LoginMethodConfigurationContent
30593103 passkeyChecked = { passkeyChecked }
30603104 />
30613105 < LoginMethodChooser
3106+ showFreePlanWarning = { showFreePlanWarning }
30623107 loginMethod = { loginMethod }
30633108 phoneLoginIDDisabled = { phoneLoginIDDisabled }
30643109 passkeyChecked = { passkeyChecked }
@@ -3260,6 +3305,7 @@ const LoginMethodConfigurationScreen: React.VFC =
32603305 const state = useMemo < FormState > ( ( ) => {
32613306 return {
32623307 resources : resourceForm . state . resources ,
3308+ planName : featureConfig . planName ,
32633309 phoneLoginIDDisabled :
32643310 featureConfig . effectiveFeatureConfig ?. identity ?. login_id ?. types ?. phone
32653311 ?. disabled ?? false ,
@@ -3268,6 +3314,7 @@ const LoginMethodConfigurationScreen: React.VFC =
32683314 ...configForm . state ,
32693315 } ;
32703316 } , [
3317+ featureConfig . planName ,
32713318 resourceForm . state . resources ,
32723319 featureConfig . effectiveFeatureConfig ?. identity ?. login_id ?. types ?. phone
32733320 ?. disabled ,
0 commit comments