diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/SignInForm.tsx b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/SignInForm.tsx
index 5fb53a8e9..facd3f7dd 100644
--- a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/SignInForm.tsx
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/SignInForm.tsx
@@ -20,7 +20,7 @@ const SignInForm = () => {
<>
{t('sign_in_exp.sign_up_and_sign_in.sign_in.title')}
-
+
{t('sign_in_exp.sign_up_and_sign_in.sign_in.description')}
{
+ const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
+ const { control } = useFormContext();
+
+ return (
+ <>
+
+ {t('sign_in_exp.sign_up_and_sign_in.social_sign_in.title')}
+
+
+
+
+ {t('sign_in_exp.sign_up_and_sign_in.social_sign_in.description')}
+
+ {
+ return ;
+ }}
+ />
+
+ >
+ );
+};
+
+export default SocialSignInForm;
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/AddButton.module.scss b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/AddButton.module.scss
new file mode 100644
index 000000000..89722b9ab
--- /dev/null
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/AddButton.module.scss
@@ -0,0 +1,37 @@
+@use '@/scss/underscore' as _;
+
+.dropdown {
+ min-width: 208px;
+}
+
+.plusIcon {
+ color: var(--color-text-secondary);
+}
+
+.title {
+ display: flex;
+ align-items: center;
+
+ .logo {
+ margin-right: _.unit(3);
+ width: 20px;
+ height: 20px;
+
+ img {
+ width: 20px;
+ height: 20px;
+ }
+ }
+
+ .name {
+ font: var(--font-body-medium);
+ }
+
+ .icon {
+ width: 16px;
+ height: 16px;
+ object-fit: cover;
+ margin-left: _.unit(1);
+ color: var(--color-text-secondary);
+ }
+}
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/AddButton.tsx b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/AddButton.tsx
new file mode 100644
index 000000000..93003825d
--- /dev/null
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/AddButton.tsx
@@ -0,0 +1,75 @@
+import Plus from '@/assets/images/plus.svg';
+import ActionMenu from '@/components/ActionMenu';
+import type { Props as ButtonProps } from '@/components/Button';
+import { DropdownItem } from '@/components/Dropdown';
+import UnnamedTrans from '@/components/UnnamedTrans';
+import ConnectorPlatformIcon from '@/icons/ConnectorPlatformIcon';
+import type { ConnectorGroup } from '@/types/connector';
+
+import * as styles from './AddButton.module.scss';
+
+type Props = {
+ options: ConnectorGroup[];
+ onSelected: (signInIdentifier: string) => void;
+ hasSelectedConnectors: boolean;
+};
+
+const AddButton = ({ options, onSelected, hasSelectedConnectors }: Props) => {
+ if (options.length === 0) {
+ return null;
+ }
+
+ const candidates = options.map(({ target, logo, name, connectors }) => ({
+ value: target,
+ title: (
+
+
+
![{target}]({logo})
+
+
+ {connectors.length > 1 &&
+ connectors
+ .filter(({ enabled }) => enabled)
+ .map(({ platform }) => (
+
+ {platform && }
+
+ ))}
+
+ ),
+ }));
+
+ const addSocialConnectorButtonProps: ButtonProps = {
+ type: 'default',
+ size: 'medium',
+ title: 'sign_in_exp.sign_up_and_sign_in.social_sign_in.add_social_connector',
+ icon: ,
+ };
+
+ const addAnotherButtonProps: ButtonProps = {
+ type: 'text',
+ size: 'small',
+ title: 'general.add_another',
+ };
+
+ return (
+
+ {candidates.map(({ value, title }) => (
+ {
+ onSelected(value);
+ }}
+ >
+ {title}
+
+ ))}
+
+ );
+};
+
+export default AddButton;
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/SelectedConnectorItem.module.scss b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/SelectedConnectorItem.module.scss
new file mode 100644
index 000000000..0f036ef0e
--- /dev/null
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/SelectedConnectorItem.module.scss
@@ -0,0 +1,49 @@
+@use '@/scss/underscore' as _;
+
+.item {
+ display: flex;
+ align-items: center;
+ margin: _.unit(2) 0;
+
+
+ .info {
+ display: flex;
+ align-items: center;
+ height: 44px;
+ width: 100%;
+ margin-right: _.unit(2);
+ padding: _.unit(3) _.unit(2);
+ background-color: var(--color-layer-2);
+ border-radius: 8px;
+ cursor: move;
+ color: var(--color-text);
+
+ .draggableIcon {
+ color: var(--color-text-secondary);
+ }
+
+ .logo {
+ margin: auto _.unit(3);
+ width: 20px;
+ height: 20px;
+
+ img {
+ width: 20px;
+ height: 20px;
+ }
+ }
+
+ .name {
+ font: var(--font-label-large);
+ }
+
+ .icon {
+ width: 16px;
+ height: 16px;
+ object-fit: cover;
+ margin-left: _.unit(1);
+ color: var(--color-text-secondary);
+ }
+ }
+}
+
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/SelectedConnectorItem.tsx b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/SelectedConnectorItem.tsx
new file mode 100644
index 000000000..acd40d1ed
--- /dev/null
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/SelectedConnectorItem.tsx
@@ -0,0 +1,44 @@
+import Draggable from '@/assets/images/draggable.svg';
+import Minus from '@/assets/images/minus.svg';
+import IconButton from '@/components/IconButton';
+import UnnamedTrans from '@/components/UnnamedTrans';
+import ConnectorPlatformIcon from '@/icons/ConnectorPlatformIcon';
+import type { ConnectorGroup } from '@/types/connector';
+
+import * as styles from './SelectedConnectorItem.module.scss';
+
+type Props = {
+ data: ConnectorGroup;
+ onDelete: (connectorTarget: string) => void;
+};
+
+const SelectedConnectorItem = ({ data: { logo, target, name, connectors }, onDelete }: Props) => {
+ return (
+
+
+
+
+
![{target}]({logo})
+
+
+ {connectors.length > 1 &&
+ connectors
+ .filter(({ enabled }) => enabled)
+ .map(({ platform }) => (
+
+ {platform && }
+
+ ))}
+
+
{
+ onDelete(target);
+ }}
+ >
+
+
+
+ );
+};
+
+export default SelectedConnectorItem;
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/index.module.scss b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/index.module.scss
new file mode 100644
index 000000000..611b534ea
--- /dev/null
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/index.module.scss
@@ -0,0 +1,12 @@
+@use '@/scss/underscore' as _;
+
+.setUpHint {
+ font: var(--font-body-medium);
+ color: var(--color-text-secondary);
+ margin-top: _.unit(2);
+
+ a {
+ color: var(--color-text-link);
+ text-decoration: none;
+ }
+}
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/index.tsx b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/index.tsx
new file mode 100644
index 000000000..7f7b39728
--- /dev/null
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/components/SocialConnectorEditBox/index.tsx
@@ -0,0 +1,94 @@
+import { ConnectorType } from '@logto/schemas';
+import { useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+
+import DragDropProvider from '@/components/Transfer/DragDropProvider';
+import DraggableItem from '@/components/Transfer/DraggableItem';
+import useConnectorGroups from '@/hooks/use-connector-groups';
+import type { ConnectorGroup } from '@/types/connector';
+
+import ConnectorSetupWarning from '../ConnectorSetupWarning';
+import AddButton from './AddButton';
+import SelectedConnectorItem from './SelectedConnectorItem';
+import * as styles from './index.module.scss';
+
+type Props = {
+ value: string[];
+ onChange: (value: string[]) => void;
+};
+
+const SocialConnectorEditBox = ({ value, onChange }: Props) => {
+ const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
+ const { data: connectorData, error } = useConnectorGroups();
+
+ if (!connectorData || error) {
+ return null;
+ }
+
+ const onMoveItem = (dragIndex: number, hoverIndex: number) => {
+ const dragItem = value[dragIndex];
+ const hoverItem = value[hoverIndex];
+
+ if (!dragItem || !hoverItem) {
+ return;
+ }
+
+ onChange(
+ value.map((value_, index) => {
+ if (index === dragIndex) {
+ return hoverItem;
+ }
+
+ if (index === hoverIndex) {
+ return dragItem;
+ }
+
+ return value_;
+ })
+ );
+ };
+
+ const selectedConnectorItems = value
+ .map((connectorTarget) => connectorData.find(({ target }) => target === connectorTarget))
+ // eslint-disable-next-line unicorn/prefer-native-coercion-functions
+ .filter((item): item is ConnectorGroup => Boolean(item));
+
+ const connectorOptions = connectorData.filter(
+ ({ target, type, enabled }) =>
+ !value.includes(target) && type === ConnectorType.Social && enabled
+ );
+
+ return (
+
+
+ {selectedConnectorItems.map((item, index) => (
+
+ {
+ onChange(value.filter((connectorTarget) => connectorTarget !== target));
+ }}
+ />
+
+ ))}
+
+
0}
+ onSelected={(target) => {
+ onChange([...value, target]);
+ }}
+ />
+
+
+ {t('sign_in_exp.sign_up_and_sign_in.social_sign_in.set_up_hint.not_in_list')}{' '}
+
+ {t('sign_in_exp.sign_up_and_sign_in.social_sign_in.set_up_hint.set_up_more')}
+ {' '}
+ {t('sign_in_exp.sign_up_and_sign_in.social_sign_in.set_up_hint.go_to')}
+
+
+ );
+};
+
+export default SocialConnectorEditBox;
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.module.scss b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.module.scss
index 946a13d28..31c0f9c5b 100644
--- a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.module.scss
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.module.scss
@@ -10,6 +10,12 @@
}
}
+.formFieldDescription {
+ font: var(--font-body-medium);
+ color: var(--color-text-secondary);
+ margin-bottom: _.unit(2);
+}
+
.socialOnlyDescription {
margin-left: _.unit(1);
color: var(--color-text-secondary);
@@ -20,8 +26,3 @@
margin-top: _.unit(3);
}
}
-
-.signInDescription {
- font: var(--font-body-medium);
- color: var(--color-text-secondary);
-}
diff --git a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.tsx b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.tsx
index e78fc8a00..37ca2b77f 100644
--- a/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.tsx
+++ b/packages/console/src/pages/SignInExperience/tabs/SignUpAndSignInTab/index.tsx
@@ -6,6 +6,7 @@ import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
import type { SignInExperienceForm } from '../../types';
import SignInForm from './SignInForm';
import SignUpForm from './SignUpForm';
+import SocialSignInForm from './SocialSignInForm';
type Props = {
defaultData: SignInExperienceForm;
@@ -25,6 +26,7 @@ const SignUpAndSignInTab = ({ defaultData, isDataDirty }: Props) => {
<>
+
>
);
diff --git a/packages/phrases/src/locales/en/translation/admin-console/sign-in-exp.ts b/packages/phrases/src/locales/en/translation/admin-console/sign-in-exp.ts
index 5d0e323a5..3b435a6df 100644
--- a/packages/phrases/src/locales/en/translation/admin-console/sign-in-exp.ts
+++ b/packages/phrases/src/locales/en/translation/admin-console/sign-in-exp.ts
@@ -62,6 +62,18 @@ const sign_in_exp = {
verification_code_auth: 'Verification code',
auth_swap_tip: 'Swap to change the priority',
},
+ social_sign_in: {
+ title: 'SOCIAL SIGN IN',
+ social_sign_in: 'Social sign in',
+ description:
+ 'Users may need to enter required identifier when register through social accounts. This was defined by your sign up identifier.',
+ add_social_connector: 'Add Social Connector',
+ set_up_hint: {
+ not_in_list: 'Not in the list?',
+ set_up_more: 'Set up more',
+ go_to: 'social connectors or go to “Connectors” section.',
+ },
+ },
},
sign_in_methods: {
title: 'SIGN-IN METHODS',
diff --git a/packages/phrases/src/locales/fr/translation/admin-console/sign-in-exp.ts b/packages/phrases/src/locales/fr/translation/admin-console/sign-in-exp.ts
index 5c76f1741..cce17e7b5 100644
--- a/packages/phrases/src/locales/fr/translation/admin-console/sign-in-exp.ts
+++ b/packages/phrases/src/locales/fr/translation/admin-console/sign-in-exp.ts
@@ -64,6 +64,18 @@ const sign_in_exp = {
verification_code_auth: 'Verification code', // UNTRANSLATED
auth_swap_tip: 'Swap to change the priority', // UNTRANSLATED
},
+ social_sign_in: {
+ title: 'SOCIAL SIGN IN', // UNTRANSLATED
+ social_sign_in: 'Social sign in', // UNTRANSLATED
+ description:
+ 'Users may need to enter required identifier when register through social accounts. This was defined by your sign up identifier.', // UNTRANSLATED
+ add_social_connector: 'Add Social Connector', // UNTRANSLATED
+ set_up_hint: {
+ not_in_list: 'Not in the list?', // UNTRANSLATED
+ set_up_more: 'Set up more', // UNTRANSLATED
+ go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
+ },
+ },
},
sign_in_methods: {
title: 'METHODES DE CONNEXION',
diff --git a/packages/phrases/src/locales/ko/translation/admin-console/sign-in-exp.ts b/packages/phrases/src/locales/ko/translation/admin-console/sign-in-exp.ts
index 1d3bf579b..6b50591d1 100644
--- a/packages/phrases/src/locales/ko/translation/admin-console/sign-in-exp.ts
+++ b/packages/phrases/src/locales/ko/translation/admin-console/sign-in-exp.ts
@@ -59,6 +59,18 @@ const sign_in_exp = {
verification_code_auth: 'Verification code', // UNTRANSLATED
auth_swap_tip: 'Swap to change the priority', // UNTRANSLATED
},
+ social_sign_in: {
+ title: 'SOCIAL SIGN IN', // UNTRANSLATED
+ social_sign_in: 'Social sign in', // UNTRANSLATED
+ description:
+ 'Users may need to enter required identifier when register through social accounts. This was defined by your sign up identifier.', // UNTRANSLATED
+ add_social_connector: 'Add Social Connector', // UNTRANSLATED
+ set_up_hint: {
+ not_in_list: 'Not in the list?', // UNTRANSLATED
+ set_up_more: 'Set up more', // UNTRANSLATED
+ go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
+ },
+ },
},
sign_in_methods: {
title: '로그인 방법',
diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/sign-in-exp.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/sign-in-exp.ts
index 0d295f9df..32535bb5e 100644
--- a/packages/phrases/src/locales/pt-pt/translation/admin-console/sign-in-exp.ts
+++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/sign-in-exp.ts
@@ -62,6 +62,18 @@ const sign_in_exp = {
verification_code_auth: 'Verification code', // UNTRANSLATED
auth_swap_tip: 'Swap to change the priority', // UNTRANSLATED
},
+ social_sign_in: {
+ title: 'SOCIAL SIGN IN', // UNTRANSLATED
+ social_sign_in: 'Social sign in', // UNTRANSLATED
+ description:
+ 'Users may need to enter required identifier when register through social accounts. This was defined by your sign up identifier.', // UNTRANSLATED
+ add_social_connector: 'Add Social Connector', // UNTRANSLATED
+ set_up_hint: {
+ not_in_list: 'Not in the list?', // UNTRANSLATED
+ set_up_more: 'Set up more', // UNTRANSLATED
+ go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
+ },
+ },
},
sign_in_methods: {
title: 'MÉTODOS DE LOGIN',
diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/sign-in-exp.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/sign-in-exp.ts
index 9233e80be..9e9f60fee 100644
--- a/packages/phrases/src/locales/tr-tr/translation/admin-console/sign-in-exp.ts
+++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/sign-in-exp.ts
@@ -63,6 +63,18 @@ const sign_in_exp = {
verification_code_auth: 'Verification code', // UNTRANSLATED
auth_swap_tip: 'Swap to change the priority', // UNTRANSLATED
},
+ social_sign_in: {
+ title: 'SOCIAL SIGN IN', // UNTRANSLATED
+ social_sign_in: 'Social sign in', // UNTRANSLATED
+ description:
+ 'Users may need to enter required identifier when register through social accounts. This was defined by your sign up identifier.', // UNTRANSLATED
+ add_social_connector: 'Add Social Connector', // UNTRANSLATED
+ set_up_hint: {
+ not_in_list: 'Not in the list?', // UNTRANSLATED
+ set_up_more: 'Set up more', // UNTRANSLATED
+ go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
+ },
+ },
},
sign_in_methods: {
title: 'OTURUM AÇMA YÖNTEMLERİ',
diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/sign-in-exp.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/sign-in-exp.ts
index 1184e2176..500544914 100644
--- a/packages/phrases/src/locales/zh-cn/translation/admin-console/sign-in-exp.ts
+++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/sign-in-exp.ts
@@ -60,6 +60,18 @@ const sign_in_exp = {
verification_code_auth: 'Verification code', // UNTRANSLATED
auth_swap_tip: 'Swap to change the priority', // UNTRANSLATED
},
+ social_sign_in: {
+ title: 'SOCIAL SIGN IN', // UNTRANSLATED
+ social_sign_in: 'Social sign in', // UNTRANSLATED
+ description:
+ 'Users may need to enter required identifier when register through social accounts. This was defined by your sign up identifier.', // UNTRANSLATED
+ add_social_connector: 'Add Social Connector', // UNTRANSLATED
+ set_up_hint: {
+ not_in_list: 'Not in the list?', // UNTRANSLATED
+ set_up_more: 'Set up more', // UNTRANSLATED
+ go_to: 'social connectors or go to “Connectors” section.', // UNTRANSLATED
+ },
+ },
},
sign_in_methods: {
title: '登录方式',