mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
feat(console): dynamic sign in methods form (#666)
This commit is contained in:
parent
6738b6a088
commit
5944ff075e
3 changed files with 72 additions and 32 deletions
|
@ -1,5 +1,5 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
import React, { InputHTMLAttributes, ReactNode, useState } from 'react';
|
||||
import React, { forwardRef, InputHTMLAttributes, ReactNode, Ref, useState } from 'react';
|
||||
|
||||
import Icon from './Icon';
|
||||
import * as styles from './index.module.scss';
|
||||
|
@ -8,16 +8,16 @@ type Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> & {
|
|||
label?: ReactNode;
|
||||
};
|
||||
|
||||
const Checkbox = ({ label, disabled, ...rest }: Props) => {
|
||||
const Checkbox = ({ label, disabled, ...rest }: Props, ref: Ref<HTMLInputElement>) => {
|
||||
const [id] = useState(nanoid());
|
||||
|
||||
return (
|
||||
<div className={styles.checkbox}>
|
||||
<input id={id} type="checkbox" disabled={disabled} {...rest} />
|
||||
<input id={id} type="checkbox" disabled={disabled} {...rest} ref={ref} />
|
||||
<Icon className={styles.icon} />
|
||||
{label && <label htmlFor={id}>{label}</label>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Checkbox;
|
||||
export default forwardRef<HTMLInputElement, Props>(Checkbox);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { SignInMethodKey } from '@logto/schemas';
|
||||
import React from 'react';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -16,8 +16,44 @@ const signInMethods = Object.values(SignInMethodKey);
|
|||
|
||||
const SignInMethodsForm = () => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { register, watch, control } = useFormContext<SignInExperienceForm>();
|
||||
const { register, watch, control, setValue } = useFormContext<SignInExperienceForm>();
|
||||
const primaryMethod = watch('signInMethods.primary');
|
||||
const enableSecondary = watch('signInMethods.enableSecondary');
|
||||
const social = watch('signInMethods.social');
|
||||
|
||||
useEffect(() => {
|
||||
if (primaryMethod) {
|
||||
// When one of the sign-in methods has been primary, it should not be able to be secondary simultaneously.
|
||||
setValue(`signInMethods.${primaryMethod}`, false);
|
||||
}
|
||||
}, [primaryMethod, setValue]);
|
||||
|
||||
const secondaryMethodsFields = useMemo(
|
||||
() =>
|
||||
signInMethods.map((method) => {
|
||||
const label = (
|
||||
<>
|
||||
{t('sign_in_exp.sign_in_methods.methods', { context: method })}
|
||||
{primaryMethod === method && (
|
||||
<span className={styles.primaryTag}>
|
||||
{t('sign_in_exp.sign_in_methods.methods_primary_tag')}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div key={method} className={styles.method}>
|
||||
<Checkbox
|
||||
label={label}
|
||||
disabled={primaryMethod === method}
|
||||
{...register(`signInMethods.${method}`)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
[primaryMethod, register, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -38,39 +74,39 @@ const SignInMethodsForm = () => {
|
|||
)}
|
||||
/>
|
||||
</FormField>
|
||||
{primaryMethod === SignInMethodKey.Social && (
|
||||
<div className={styles.primarySocial}>
|
||||
<Controller
|
||||
name="socialSignInConnectorIds"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<ConnectorsTransfer value={value} onChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<FormField isRequired title="admin_console.sign_in_exp.sign_in_methods.enable_secondary">
|
||||
<Switch
|
||||
{...register('signInMethods.enableSecondary', { required: true })}
|
||||
label={t('sign_in_exp.sign_in_methods.enable_secondary_description')}
|
||||
/>
|
||||
{signInMethods.map((method) => (
|
||||
<div key={method} className={styles.method}>
|
||||
<Checkbox
|
||||
label={
|
||||
<>
|
||||
{t('sign_in_exp.sign_in_methods.methods', { context: method })}
|
||||
{primaryMethod === method && (
|
||||
<span className={styles.primaryTag}>
|
||||
{t('sign_in_exp.sign_in_methods.methods_primary_tag')}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
disabled={primaryMethod === method}
|
||||
{...register(`signInMethods.${method}`)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</FormField>
|
||||
<FormField title="admin_console.sign_in_exp.sign_in_methods.define_social_methods">
|
||||
<Controller
|
||||
name="socialSignInConnectorIds"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<ConnectorsTransfer value={value} onChange={onChange} />
|
||||
{enableSecondary && (
|
||||
<>
|
||||
{secondaryMethodsFields}
|
||||
{social && (
|
||||
<FormField title="admin_console.sign_in_exp.sign_in_methods.define_social_methods">
|
||||
<Controller
|
||||
name="socialSignInConnectorIds"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<ConnectorsTransfer value={value} onChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
</FormField>
|
||||
)}
|
||||
/>
|
||||
</FormField>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -13,3 +13,7 @@
|
|||
.method {
|
||||
margin-top: _.unit(2);
|
||||
}
|
||||
|
||||
.primarySocial {
|
||||
margin-top: _.unit(2);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue