mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
refactor(ui): refactor social signin callback flow (#967)
* refactor(ui): refactor social signin callback flow refactor social signin callback flow * fix(ui): change file structure change file structure
This commit is contained in:
parent
6b53ed5f4f
commit
7015d81378
8 changed files with 74 additions and 46 deletions
|
@ -15,6 +15,7 @@ import Register from './pages/Register';
|
|||
import SecondarySignIn from './pages/SecondarySignIn';
|
||||
import SignIn from './pages/SignIn';
|
||||
import SocialRegister from './pages/SocialRegister';
|
||||
import SocialSignInCallback from './pages/SocialSignInCallback';
|
||||
import getSignInExperienceSettings from './utils/sign-in-experience';
|
||||
|
||||
import './scss/normalized.scss';
|
||||
|
@ -54,7 +55,7 @@ const App = () => {
|
|||
<Route path="/" element={<Navigate replace to="/sign-in" />} />
|
||||
<Route path="/sign-in" element={<SignIn />} />
|
||||
<Route path="/sign-in/consent" element={<Consent />} />
|
||||
<Route path="/sign-in/callback/:connector" element={<SignIn />} />
|
||||
<Route path="/sign-in/callback/:connector" element={<SocialSignInCallback />} />
|
||||
<Route path="/sign-in/:method" element={<SecondarySignIn />} />
|
||||
<Route path="/register" element={<Register />} />
|
||||
<Route path="/register/:method" element={<Register />} />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
|
||||
import useSocialSignInListener from '@/hooks/use-social-signin-listener';
|
||||
import useNativeMessageListener from '@/hooks/use-native-message-listener';
|
||||
|
||||
import SocialSignInList from '../SocialSignInList';
|
||||
|
||||
|
@ -11,7 +11,7 @@ type Props = {
|
|||
};
|
||||
|
||||
const PrimarySocialSignIn = ({ className }: Props) => {
|
||||
useSocialSignInListener();
|
||||
useNativeMessageListener();
|
||||
|
||||
return <SocialSignInList className={className} />;
|
||||
};
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { fireEvent, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import renderWithPageContext from '@/__mocks__/RenderWithPageContext';
|
||||
import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider';
|
||||
import { socialConnectors, mockSignInExperienceSettings } from '@/__mocks__/logto';
|
||||
import * as socialSignInApi from '@/apis/social';
|
||||
import { generateState, storeState } from '@/hooks/utils';
|
||||
|
||||
import SecondarySocialSignIn, { defaultSize } from '.';
|
||||
|
||||
|
@ -17,10 +16,6 @@ describe('SecondarySocialSignIn', () => {
|
|||
.spyOn(socialSignInApi, 'invokeSocialSignIn')
|
||||
.mockResolvedValue({ redirectTo: `${mockOrigin}/callback` });
|
||||
|
||||
const signInWithSocialSpy = jest
|
||||
.spyOn(socialSignInApi, 'signInWithSocial')
|
||||
.mockResolvedValue({ redirectTo: `${mockOrigin}/callback` });
|
||||
|
||||
beforeEach(() => {
|
||||
/* eslint-disable @silverhand/fp/no-mutation */
|
||||
// @ts-expect-error mock global object
|
||||
|
@ -126,34 +121,4 @@ describe('SecondarySocialSignIn', () => {
|
|||
expect(logtoNativeSdk?.getPostMessage).toBeCalled();
|
||||
}
|
||||
});
|
||||
|
||||
it('callback validation and signIn with social', async () => {
|
||||
const state = generateState();
|
||||
storeState(state, 'github');
|
||||
|
||||
/* eslint-disable @silverhand/fp/no-mutating-methods */
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
href: `/sign-in/callback?state=${state}&code=foo`,
|
||||
search: `?state=${state}&code=foo`,
|
||||
pathname: '/sign-in/callback',
|
||||
assign: jest.fn(),
|
||||
},
|
||||
});
|
||||
/* eslint-enable @silverhand/fp/no-mutating-methods */
|
||||
|
||||
renderWithPageContext(
|
||||
<SettingsProvider>
|
||||
<MemoryRouter initialEntries={['/sign-in/callback/github']}>
|
||||
<Routes>
|
||||
<Route path="/sign-in/callback/:connector" element={<SecondarySocialSignIn />} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</SettingsProvider>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(signInWithSocialSpy).toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useMemo, useState, useRef } from 'react';
|
||||
|
||||
import useNativeMessageListener from '@/hooks/use-native-message-listener';
|
||||
import usePlatform from '@/hooks/use-platform';
|
||||
import useSocial from '@/hooks/use-social';
|
||||
import useSocialSignInListener from '@/hooks/use-social-signin-listener';
|
||||
|
||||
import SocialSignInDropdown from '../SocialSignInDropdown';
|
||||
import SocialSignInIconList from '../SocialSignInIconList';
|
||||
|
@ -20,7 +20,7 @@ const SecondarySocialSignIn = ({ className }: Props) => {
|
|||
const moreButtonRef = useRef<HTMLButtonElement>(null);
|
||||
const { isMobile } = usePlatform();
|
||||
|
||||
useSocialSignInListener();
|
||||
useNativeMessageListener();
|
||||
|
||||
const isCollapsed = socialConnectors.length > defaultSize;
|
||||
|
||||
|
|
|
@ -43,7 +43,10 @@ const useSocialCallbackHandler = () => {
|
|||
// Web/Mobile-Web redirect to sign-in/callback page to login
|
||||
if (platform === 'web') {
|
||||
navigate(
|
||||
new URL(`${location.origin}/sign-in/callback/${connectorId}/${window.location.search}`),
|
||||
{
|
||||
pathname: `/sign-in/callback/${connectorId}`,
|
||||
search: window.location.search,
|
||||
},
|
||||
{
|
||||
replace: true,
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import { signInWithSocial } from '@/apis/social';
|
|||
import { parseQueryParameters } from '@/utils';
|
||||
|
||||
import useApi, { ErrorHandlers } from './use-api';
|
||||
import useNativeMessageListener from './use-native-message-listener';
|
||||
import { PageContext } from './use-page-context';
|
||||
import { stateValidation } from './utils';
|
||||
|
||||
|
@ -16,8 +15,6 @@ const useSocialSignInListener = () => {
|
|||
const parameters = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useNativeMessageListener();
|
||||
|
||||
const signInWithSocialErrorHandlers: ErrorHandlers = useMemo(
|
||||
() => ({
|
||||
'user.identity_not_exists': (error) => {
|
||||
|
@ -58,7 +55,7 @@ const useSocialSignInListener = () => {
|
|||
|
||||
// Social Sign-In Callback Handler
|
||||
useEffect(() => {
|
||||
if (!location.pathname.includes('/sign-in/callback') || !parameters.connector) {
|
||||
if (!parameters.connector) {
|
||||
return;
|
||||
}
|
||||
|
49
packages/ui/src/pages/SocialSignInCallback/index.test.tsx
Normal file
49
packages/ui/src/pages/SocialSignInCallback/index.test.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
|
||||
import renderWithPageContext from '@/__mocks__/RenderWithPageContext';
|
||||
import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider';
|
||||
import * as socialSignInApi from '@/apis/social';
|
||||
import { generateState, storeState } from '@/hooks/utils';
|
||||
|
||||
import SocialCallback from '.';
|
||||
|
||||
const origin = 'http://localhost:3000';
|
||||
|
||||
describe('SocialCallbackPage with code', () => {
|
||||
const signInWithSocialSpy = jest
|
||||
.spyOn(socialSignInApi, 'signInWithSocial')
|
||||
.mockResolvedValue({ redirectTo: `/sign-in` });
|
||||
|
||||
it('callback validation and signIn with social', async () => {
|
||||
const state = generateState();
|
||||
storeState(state, 'github');
|
||||
|
||||
/* eslint-disable @silverhand/fp/no-mutating-methods */
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
origin,
|
||||
href: `/sign-in/callback?state=${state}&code=foo`,
|
||||
search: `?state=${state}&code=foo`,
|
||||
pathname: '/sign-in/callback',
|
||||
assign: jest.fn(),
|
||||
},
|
||||
});
|
||||
/* eslint-enable @silverhand/fp/no-mutating-methods */
|
||||
|
||||
renderWithPageContext(
|
||||
<SettingsProvider>
|
||||
<MemoryRouter initialEntries={['/sign-in/callback/github']}>
|
||||
<Routes>
|
||||
<Route path="/sign-in/callback/:connector" element={<SocialCallback />} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</SettingsProvider>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(signInWithSocialSpy).toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
13
packages/ui/src/pages/SocialSignInCallback/index.tsx
Normal file
13
packages/ui/src/pages/SocialSignInCallback/index.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
|
||||
import useSocialSignInListener from '@/hooks/use-social-sign-in-listener';
|
||||
|
||||
import SignIn from '../SignIn';
|
||||
|
||||
const SocialSignInCallback = () => {
|
||||
useSocialSignInListener();
|
||||
|
||||
return <SignIn />;
|
||||
};
|
||||
|
||||
export default SocialSignInCallback;
|
Loading…
Reference in a new issue