0
Fork 0
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:
simeng-li 2022-05-24 16:43:14 +08:00 committed by GitHub
parent cf360b9c15
commit 8060ec4941
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 31 deletions

View file

@ -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];

View file

@ -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' },
]);
});
});

View file

@ -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());
};

View file

@ -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;