0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-24 22:41:28 -05:00

fix(ui): fix social native interaction bug (#772)

* fix(ui): fix social native sdk data namespace

fix social native sdk data namespace

* refactor(ui): refactor nativeSDK callbackUrl

 refactor nativeSDK callbackUrl
`

* refactor(ui): return result from api

return result from api

* fix(ui): should not show error message on social bind account

should not show error message on social bind account
This commit is contained in:
simeng-li 2022-05-10 12:20:15 +08:00 committed by GitHub
parent 475cb52d8e
commit 2161856bcd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 56 deletions

View file

@ -17,7 +17,7 @@ type Props = {
const PrimarySocialSignIn = ({ className, isPopup = false, onSocialSignInCallback }: Props) => { const PrimarySocialSignIn = ({ className, isPopup = false, onSocialSignInCallback }: Props) => {
const [showAll, setShowAll] = useState(false); const [showAll, setShowAll] = useState(false);
const { invokeSocialSignIn, socialConnectors } = useSocial({ onSocialSignInCallback }); const { invokeSocialSignIn, socialConnectors } = useSocial();
const isOverSize = socialConnectors.length > defaultSize; const isOverSize = socialConnectors.length > defaultSize;
const fullDisplay = isPopup || !isOverSize; const fullDisplay = isPopup || !isOverSize;
@ -37,7 +37,7 @@ const PrimarySocialSignIn = ({ className, isPopup = false, onSocialSignInCallbac
className={styles.socialLinkButton} className={styles.socialLinkButton}
connector={connector} connector={connector}
onClick={() => { onClick={() => {
void invokeSocialSignIn(connector.id); void invokeSocialSignIn(connector.id, onSocialSignInCallback);
}} }}
/> />
))} ))}

View file

@ -28,7 +28,7 @@ describe('SecondarySocialSignIn', () => {
platform: 'web', platform: 'web',
getPostMessage: jest.fn(() => jest.fn()), getPostMessage: jest.fn(() => jest.fn()),
callbackLink: '/logto:', callbackLink: '/logto:',
supportedSocialConnectors: socialConnectors.map(({ id }) => id), supportedSocialConnectorIds: socialConnectors.map(({ id }) => id),
}; };
/* eslint-enable @silverhand/fp/no-mutation */ /* eslint-enable @silverhand/fp/no-mutation */
}); });

View file

@ -9,7 +9,7 @@ import { PageContext } from '@/hooks/use-page-context';
type UseApi<T extends any[], U> = { type UseApi<T extends any[], U> = {
result?: U; result?: U;
error: RequestErrorBody | undefined; error: RequestErrorBody | undefined;
run: (...args: T) => Promise<void>; run: (...args: T) => Promise<U | undefined>;
}; };
export type ErrorHandlers = { export type ErrorHandlers = {
@ -38,6 +38,8 @@ function useApi<Args extends any[], Response>(
try { try {
const result = await api(...args); const result = await api(...args);
setResult(result); setResult(result);
return result;
} catch (error: unknown) { } catch (error: unknown) {
if (error instanceof HTTPError && error.response.body) { if (error instanceof HTTPError && error.response.body) {
const kyError = await error.response.json<RequestErrorBody>(); const kyError = await error.response.json<RequestErrorBody>();

View file

@ -23,10 +23,6 @@ type State = {
callbackLink?: string; callbackLink?: string;
}; };
type Options = {
onSocialSignInCallback?: () => void;
};
const storageKeyPrefix = 'social_auth_state'; const storageKeyPrefix = 'social_auth_state';
const getLogtoNativeSdk = () => { const getLogtoNativeSdk = () => {
@ -69,7 +65,7 @@ const isNativeWebview = () => {
return ['ios', 'android'].includes(platform); return ['ios', 'android'].includes(platform);
}; };
const useSocial = (options?: Options) => { const useSocial = () => {
const { setToast, experienceSettings } = useContext(PageContext); const { setToast, experienceSettings } = useContext(PageContext);
const { termsValidation } = useTerms(); const { termsValidation } = useTerms();
const parameters = useParams(); const parameters = useParams();
@ -86,31 +82,26 @@ const useSocial = (options?: Options) => {
}, },
}); });
} }
setToast(error.message);
}, },
}), }),
[navigate, parameters.connector, setToast] [navigate, parameters.connector]
); );
// Filter native supported social connectors // Filter native supported social connectors
const socialConnectors = useMemo( const socialConnectors = useMemo(
() => () =>
(experienceSettings?.socialConnectors ?? []).filter(({ id }) => { (experienceSettings?.socialConnectors ?? []).filter(({ id }) => {
return !isNativeWebview() || getLogtoNativeSdk()?.supportedSocialConnectors.includes(id); return !isNativeWebview() || getLogtoNativeSdk()?.supportedSocialConnectorIds.includes(id);
}), }),
[experienceSettings?.socialConnectors] [experienceSettings?.socialConnectors]
); );
const { result: invokeSocialSignInResult, run: asyncInvokeSocialSignIn } = const { run: asyncInvokeSocialSignIn } = useApi(invokeSocialSignIn);
useApi(invokeSocialSignIn);
const { result: signInWithSocialResult, run: asyncSignInWithSocial } = useApi( const { run: asyncSignInWithSocial } = useApi(signInWithSocial, signInWithSocialErrorHandlers);
signInWithSocial,
signInWithSocialErrorHandlers
);
const invokeSocialSignInHandler = useCallback( const invokeSocialSignInHandler = useCallback(
async (connectorId: string) => { async (connectorId: string, callback?: () => void) => {
if (!termsValidation()) { if (!termsValidation()) {
return; return;
} }
@ -120,23 +111,52 @@ const useSocial = (options?: Options) => {
const { origin } = window.location; const { origin } = window.location;
return asyncInvokeSocialSignIn(connectorId, state, `${origin}/callback/${connectorId}`); const result = await asyncInvokeSocialSignIn(
connectorId,
state,
`${origin}/callback/${connectorId}`
);
if (!result?.redirectTo) {
return;
}
// Callback hook to close the social sign in modal
callback?.();
// Invoke Native Social Sign In flow
if (isNativeWebview()) {
getLogtoNativeSdk()?.getPostMessage()({
callbackUri: `${origin}/callback/${connectorId}`,
redirectTo: result.redirectTo,
});
return;
}
// Invoke Web Social Sign In flow
window.location.assign(result.redirectTo);
}, },
[asyncInvokeSocialSignIn, termsValidation] [asyncInvokeSocialSignIn, termsValidation]
); );
const signInWithSocialHandler = useCallback( const signInWithSocialHandler = useCallback(
(connectorId: string, state: string, code: string) => { async (connectorId: string, state: string, code: string) => {
if (!stateValidation(state, connectorId)) { if (!stateValidation(state, connectorId)) {
setToast(t('error.invalid_connector_auth')); setToast(t('error.invalid_connector_auth'));
return; return;
} }
void asyncSignInWithSocial({
const result = await asyncSignInWithSocial({
connectorId, connectorId,
code, code,
redirectUri: `${origin}/callback/${connectorId}`, redirectUri: `${origin}/callback/${connectorId}`,
}); });
if (result?.redirectTo) {
window.location.assign(result.redirectTo);
}
}, },
[asyncSignInWithSocial, setToast, t] [asyncSignInWithSocial, setToast, t]
); );
@ -181,38 +201,6 @@ const useSocial = (options?: Options) => {
window.location.assign(new URL(`${callbackLink}${window.location.search}`)); window.location.assign(new URL(`${callbackLink}${window.location.search}`));
}, [parameters.connector, setToast, t]); }, [parameters.connector, setToast, t]);
// InvokeSocialSignIn Callback
useEffect(() => {
const { redirectTo } = invokeSocialSignInResult ?? {};
if (!redirectTo) {
return;
}
// Callback hook to close the social sign in modal
options?.onSocialSignInCallback?.();
// Invoke Native Social Sign In flow
if (isNativeWebview()) {
getLogtoNativeSdk()?.getPostMessage()({
callbackUri: redirectTo.replace('/callback', '/sign-in/callback'),
redirectTo,
});
return;
}
// Invoke Web Social Sign In flow
window.location.assign(redirectTo);
}, [invokeSocialSignInResult, options]);
// SignInWithSocial Callback
useEffect(() => {
if (signInWithSocialResult?.redirectTo) {
window.location.assign(signInWithSocialResult.redirectTo);
}
}, [signInWithSocialResult]);
// Social Sign-In Callback Handler // Social Sign-In Callback Handler
useEffect(() => { useEffect(() => {
if (!location.pathname.includes('/sign-in/callback') || !parameters.connector) { if (!location.pathname.includes('/sign-in/callback') || !parameters.connector) {
@ -225,7 +213,7 @@ const useSocial = (options?: Options) => {
return; return;
} }
signInWithSocialHandler(parameters.connector, state, code); void signInWithSocialHandler(parameters.connector, state, code);
}, [parameters.connector, signInWithSocialHandler]); }, [parameters.connector, signInWithSocialHandler]);
// Monitor Native Error Message // Monitor Native Error Message

View file

@ -4,7 +4,7 @@ type LogtoNativeSdkInfo = {
platform: 'ios' | 'android'; platform: 'ios' | 'android';
callbackLink: string; callbackLink: string;
getPostMessage: () => (data: { callbackUri?: string; redirectTo?: string }) => void; getPostMessage: () => (data: { callbackUri?: string; redirectTo?: string }) => void;
supportedSocialConnectors: string[]; supportedSocialConnectorIds: string[];
}; };
declare const logtoNativeSdk: LogtoNativeSdkInfo | undefined; declare const logtoNativeSdk: LogtoNativeSdkInfo | undefined;