mirror of
https://github.com/logto-io/logto.git
synced 2024-12-23 20:33:16 -05:00
refactor(ui): add preview social connectors filter (#932)
* refactor(ui): add preview social connectors filter add preview social connectors filter * fix(ui): typo fix typo fix
This commit is contained in:
parent
cf360b9c15
commit
8060ec4941
4 changed files with 125 additions and 31 deletions
|
@ -4,16 +4,17 @@ import i18next from 'i18next';
|
|||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { Context } from '@/hooks/use-page-context';
|
||||
import { filterPreviewSocialConnectors } from '@/hooks/utils';
|
||||
import initI18n from '@/i18n/init';
|
||||
import { SignInExperienceSettingsResponse } from '@/types';
|
||||
import { SignInExperienceSettingsResponse, Platform } from '@/types';
|
||||
import { parseQueryParameters } from '@/utils';
|
||||
import { parseSignInExperienceSettings } from '@/utils/sign-in-experience';
|
||||
import { getPrimarySignInMethod, getSecondarySignInMethods } from '@/utils/sign-in-experience';
|
||||
|
||||
type PreviewConfig = {
|
||||
signInExperience: SignInExperienceSettingsResponse;
|
||||
language: Language;
|
||||
mode: AppearanceMode.LightMode | AppearanceMode.DarkMode;
|
||||
platform: 'web' | 'mobile';
|
||||
platform: Platform;
|
||||
};
|
||||
|
||||
const usePreview = (context: Context): [boolean, PreviewConfig?] => {
|
||||
|
@ -53,20 +54,31 @@ const usePreview = (context: Context): [boolean, PreviewConfig?] => {
|
|||
return;
|
||||
}
|
||||
|
||||
const { signInExperience, language, mode, platform } = previewConfig;
|
||||
const experienceSettings = parseSignInExperienceSettings(signInExperience);
|
||||
const {
|
||||
signInExperience: { signInMethods, socialConnectors, branding, ...rest },
|
||||
language,
|
||||
mode,
|
||||
platform,
|
||||
} = previewConfig;
|
||||
|
||||
const experienceSettings = {
|
||||
...rest,
|
||||
branding: {
|
||||
...branding,
|
||||
isDarkModeEnabled: false, // Disable theme mode auto detection on preview
|
||||
},
|
||||
primarySignInMethod: getPrimarySignInMethod(signInMethods),
|
||||
secondarySignInMethods: getSecondarySignInMethods(signInMethods),
|
||||
socialConnectors: filterPreviewSocialConnectors(platform, socialConnectors),
|
||||
};
|
||||
|
||||
void i18next.changeLanguage(language);
|
||||
|
||||
setTheme(mode);
|
||||
|
||||
setPlatform(platform);
|
||||
setExperienceSettings({
|
||||
...experienceSettings,
|
||||
branding: {
|
||||
...experienceSettings.branding,
|
||||
isDarkModeEnabled: false, // Disable theme mode auto detection on preview
|
||||
},
|
||||
});
|
||||
|
||||
setExperienceSettings(experienceSettings);
|
||||
}, [isPreview, previewConfig, setExperienceSettings, setPlatform, setTheme]);
|
||||
|
||||
return [isPreview, previewConfig];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ConnectorData } from '@/types';
|
||||
|
||||
import { filterSocialConnectors } from './utils';
|
||||
import { filterSocialConnectors, filterPreviewSocialConnectors } from './utils';
|
||||
|
||||
const mockConnectors = [
|
||||
{ platform: 'Web', target: 'facebook' },
|
||||
|
@ -63,3 +63,30 @@ describe('filterSocialConnectors', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterPreviewSocialConnectors', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('undefined input should return empty list', () => {
|
||||
expect(filterPreviewSocialConnectors('web')).toEqual([]);
|
||||
expect(filterPreviewSocialConnectors('mobile')).toEqual([]);
|
||||
});
|
||||
|
||||
it('filter Web Connectors', () => {
|
||||
expect(filterPreviewSocialConnectors('web', mockConnectors)).toEqual([
|
||||
{ platform: 'Web', target: 'facebook' },
|
||||
{ platform: 'Web', target: 'google' },
|
||||
{ platform: 'Universal', target: 'WeChat' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('filter Native Connectors', () => {
|
||||
expect(filterPreviewSocialConnectors('mobile', mockConnectors)).toEqual([
|
||||
{ platform: 'Universal', target: 'facebook' },
|
||||
{ platform: 'Native', target: 'WeChat' },
|
||||
{ platform: 'Native', target: 'Alipay' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ConnectorData } from '@/types';
|
||||
import { ConnectorData, Platform } from '@/types';
|
||||
import { generateRandomString } from '@/utils';
|
||||
|
||||
/**
|
||||
|
@ -71,7 +71,7 @@ export const filterSocialConnectors = (socialConnectors?: ConnectorData[]) => {
|
|||
/**
|
||||
* Browser Environment
|
||||
* Accepts both web and universal platform connectors.
|
||||
* Insert universal connectors only if there is no web platform connector provided with the same target.
|
||||
* Insert universal connectors only if there is no web platform connector provided with the same target.
|
||||
* Web platform has higher priority.
|
||||
**/
|
||||
|
||||
|
@ -95,7 +95,7 @@ export const filterSocialConnectors = (socialConnectors?: ConnectorData[]) => {
|
|||
/**
|
||||
* Native Webview Environment
|
||||
* Accepts both native and universal platform connectors.
|
||||
* Insert universal connectors only if there is no native platform connector provided with the same target.
|
||||
* Insert universal connectors only if there is no native platform connector provided with the same target.
|
||||
* Native platform has higher priority.
|
||||
**/
|
||||
|
||||
|
@ -126,3 +126,63 @@ export const filterSocialConnectors = (socialConnectors?: ConnectorData[]) => {
|
|||
|
||||
return Array.from(connectorMap.values());
|
||||
};
|
||||
|
||||
/**
|
||||
* Social Connectors Filter Utility Methods used in preview mode only
|
||||
*/
|
||||
export const filterPreviewSocialConnectors = (
|
||||
previewPlatform: Platform,
|
||||
socialConnectors?: ConnectorData[]
|
||||
) => {
|
||||
if (!socialConnectors) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const connectorMap = new Map<string, ConnectorData>();
|
||||
|
||||
/**
|
||||
* Browser Environment
|
||||
* Accepts both web and universal platform connectors.
|
||||
* Insert universal connectors only if there is no web platform connector provided with the same target.
|
||||
* Web platform has higher priority.
|
||||
**/
|
||||
|
||||
if (previewPlatform === 'web') {
|
||||
for (const connector of socialConnectors) {
|
||||
const { platform, target } = connector;
|
||||
|
||||
if (platform === 'Native') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (platform === 'Web' || !connectorMap.get(target)) {
|
||||
connectorMap.set(target, connector);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(connectorMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Native Webview Environment
|
||||
* Accepts both native and universal platform connectors.
|
||||
* Insert universal connectors only if there is no native platform connector provided with the same target.
|
||||
* Native platform has higher priority.
|
||||
**/
|
||||
|
||||
for (const connector of socialConnectors) {
|
||||
const { platform, target } = connector;
|
||||
|
||||
if (platform === 'Web') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (platform === 'Native' || !connectorMap.get(target)) {
|
||||
connectorMap.set(target, connector);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(connectorMap.values());
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getSignInExperience } from '@/apis/settings';
|
|||
import { filterSocialConnectors } from '@/hooks/utils';
|
||||
import { SignInMethod, SignInExperienceSettingsResponse, SignInExperienceSettings } from '@/types';
|
||||
|
||||
const getPrimarySignInMethod = (signInMethods: SignInMethods) => {
|
||||
export const getPrimarySignInMethod = (signInMethods: SignInMethods) => {
|
||||
for (const [key, value] of Object.entries(signInMethods)) {
|
||||
if (value === 'primary') {
|
||||
return key as keyof SignInMethods;
|
||||
|
@ -19,7 +19,7 @@ const getPrimarySignInMethod = (signInMethods: SignInMethods) => {
|
|||
return 'username';
|
||||
};
|
||||
|
||||
const getSecondarySignInMethods = (signInMethods: SignInMethods) =>
|
||||
export const getSecondarySignInMethods = (signInMethods: SignInMethods) =>
|
||||
Object.entries(signInMethods).reduce<SignInMethod[]>((methods, [key, value]) => {
|
||||
if (value === 'secondary') {
|
||||
return [...methods, key as SignInMethod];
|
||||
|
@ -28,21 +28,16 @@ const getSecondarySignInMethods = (signInMethods: SignInMethods) =>
|
|||
return methods;
|
||||
}, []);
|
||||
|
||||
export const parseSignInExperienceSettings = ({
|
||||
signInMethods,
|
||||
socialConnectors,
|
||||
...rest
|
||||
}: SignInExperienceSettingsResponse) => ({
|
||||
...rest,
|
||||
primarySignInMethod: getPrimarySignInMethod(signInMethods),
|
||||
secondarySignInMethods: getSecondarySignInMethods(signInMethods),
|
||||
socialConnectors: filterSocialConnectors(socialConnectors),
|
||||
});
|
||||
|
||||
const getSignInExperienceSettings = async (): Promise<SignInExperienceSettings> => {
|
||||
const response = await getSignInExperience<SignInExperienceSettingsResponse>();
|
||||
const { signInMethods, socialConnectors, ...rest } =
|
||||
await getSignInExperience<SignInExperienceSettingsResponse>();
|
||||
|
||||
return parseSignInExperienceSettings(response);
|
||||
return {
|
||||
...rest,
|
||||
primarySignInMethod: getPrimarySignInMethod(signInMethods),
|
||||
secondarySignInMethods: getSecondarySignInMethods(signInMethods),
|
||||
socialConnectors: filterSocialConnectors(socialConnectors),
|
||||
};
|
||||
};
|
||||
|
||||
export default getSignInExperienceSettings;
|
||||
|
|
Loading…
Reference in a new issue