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:
parent
475cb52d8e
commit
2161856bcd
5 changed files with 46 additions and 56 deletions
|
@ -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);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -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 */
|
||||||
});
|
});
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
|
@ -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
|
||||||
|
|
2
packages/ui/src/include.d/global.d.ts
vendored
2
packages/ui/src/include.d/global.d.ts
vendored
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue