mirror of
https://github.com/logto-io/logto.git
synced 2025-01-20 21:32:31 -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 { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { Context } from '@/hooks/use-page-context';
|
import { Context } from '@/hooks/use-page-context';
|
||||||
|
import { filterPreviewSocialConnectors } from '@/hooks/utils';
|
||||||
import initI18n from '@/i18n/init';
|
import initI18n from '@/i18n/init';
|
||||||
import { SignInExperienceSettingsResponse } from '@/types';
|
import { SignInExperienceSettingsResponse, Platform } from '@/types';
|
||||||
import { parseQueryParameters } from '@/utils';
|
import { parseQueryParameters } from '@/utils';
|
||||||
import { parseSignInExperienceSettings } from '@/utils/sign-in-experience';
|
import { getPrimarySignInMethod, getSecondarySignInMethods } from '@/utils/sign-in-experience';
|
||||||
|
|
||||||
type PreviewConfig = {
|
type PreviewConfig = {
|
||||||
signInExperience: SignInExperienceSettingsResponse;
|
signInExperience: SignInExperienceSettingsResponse;
|
||||||
language: Language;
|
language: Language;
|
||||||
mode: AppearanceMode.LightMode | AppearanceMode.DarkMode;
|
mode: AppearanceMode.LightMode | AppearanceMode.DarkMode;
|
||||||
platform: 'web' | 'mobile';
|
platform: Platform;
|
||||||
};
|
};
|
||||||
|
|
||||||
const usePreview = (context: Context): [boolean, PreviewConfig?] => {
|
const usePreview = (context: Context): [boolean, PreviewConfig?] => {
|
||||||
|
@ -53,20 +54,31 @@ const usePreview = (context: Context): [boolean, PreviewConfig?] => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { signInExperience, language, mode, platform } = previewConfig;
|
const {
|
||||||
const experienceSettings = parseSignInExperienceSettings(signInExperience);
|
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);
|
void i18next.changeLanguage(language);
|
||||||
|
|
||||||
setTheme(mode);
|
setTheme(mode);
|
||||||
|
|
||||||
setPlatform(platform);
|
setPlatform(platform);
|
||||||
setExperienceSettings({
|
|
||||||
...experienceSettings,
|
setExperienceSettings(experienceSettings);
|
||||||
branding: {
|
|
||||||
...experienceSettings.branding,
|
|
||||||
isDarkModeEnabled: false, // Disable theme mode auto detection on preview
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, [isPreview, previewConfig, setExperienceSettings, setPlatform, setTheme]);
|
}, [isPreview, previewConfig, setExperienceSettings, setPlatform, setTheme]);
|
||||||
|
|
||||||
return [isPreview, previewConfig];
|
return [isPreview, previewConfig];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ConnectorData } from '@/types';
|
import { ConnectorData } from '@/types';
|
||||||
|
|
||||||
import { filterSocialConnectors } from './utils';
|
import { filterSocialConnectors, filterPreviewSocialConnectors } from './utils';
|
||||||
|
|
||||||
const mockConnectors = [
|
const mockConnectors = [
|
||||||
{ platform: 'Web', target: 'facebook' },
|
{ 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';
|
import { generateRandomString } from '@/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,3 +126,63 @@ export const filterSocialConnectors = (socialConnectors?: ConnectorData[]) => {
|
||||||
|
|
||||||
return Array.from(connectorMap.values());
|
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 { filterSocialConnectors } from '@/hooks/utils';
|
||||||
import { SignInMethod, SignInExperienceSettingsResponse, SignInExperienceSettings } from '@/types';
|
import { SignInMethod, SignInExperienceSettingsResponse, SignInExperienceSettings } from '@/types';
|
||||||
|
|
||||||
const getPrimarySignInMethod = (signInMethods: SignInMethods) => {
|
export const getPrimarySignInMethod = (signInMethods: SignInMethods) => {
|
||||||
for (const [key, value] of Object.entries(signInMethods)) {
|
for (const [key, value] of Object.entries(signInMethods)) {
|
||||||
if (value === 'primary') {
|
if (value === 'primary') {
|
||||||
return key as keyof SignInMethods;
|
return key as keyof SignInMethods;
|
||||||
|
@ -19,7 +19,7 @@ const getPrimarySignInMethod = (signInMethods: SignInMethods) => {
|
||||||
return 'username';
|
return 'username';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSecondarySignInMethods = (signInMethods: SignInMethods) =>
|
export const getSecondarySignInMethods = (signInMethods: SignInMethods) =>
|
||||||
Object.entries(signInMethods).reduce<SignInMethod[]>((methods, [key, value]) => {
|
Object.entries(signInMethods).reduce<SignInMethod[]>((methods, [key, value]) => {
|
||||||
if (value === 'secondary') {
|
if (value === 'secondary') {
|
||||||
return [...methods, key as SignInMethod];
|
return [...methods, key as SignInMethod];
|
||||||
|
@ -28,21 +28,16 @@ const getSecondarySignInMethods = (signInMethods: SignInMethods) =>
|
||||||
return methods;
|
return methods;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
export const parseSignInExperienceSettings = ({
|
const getSignInExperienceSettings = async (): Promise<SignInExperienceSettings> => {
|
||||||
signInMethods,
|
const { signInMethods, socialConnectors, ...rest } =
|
||||||
socialConnectors,
|
await getSignInExperience<SignInExperienceSettingsResponse>();
|
||||||
...rest
|
|
||||||
}: SignInExperienceSettingsResponse) => ({
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
primarySignInMethod: getPrimarySignInMethod(signInMethods),
|
primarySignInMethod: getPrimarySignInMethod(signInMethods),
|
||||||
secondarySignInMethods: getSecondarySignInMethods(signInMethods),
|
secondarySignInMethods: getSecondarySignInMethods(signInMethods),
|
||||||
socialConnectors: filterSocialConnectors(socialConnectors),
|
socialConnectors: filterSocialConnectors(socialConnectors),
|
||||||
});
|
};
|
||||||
|
|
||||||
const getSignInExperienceSettings = async (): Promise<SignInExperienceSettings> => {
|
|
||||||
const response = await getSignInExperience<SignInExperienceSettingsResponse>();
|
|
||||||
|
|
||||||
return parseSignInExperienceSettings(response);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default getSignInExperienceSettings;
|
export default getSignInExperienceSettings;
|
||||||
|
|
Loading…
Add table
Reference in a new issue