mirror of
https://github.com/logto-io/logto.git
synced 2025-03-10 22:22:45 -05:00
refactor(ui): extract useBindSocial hook (#667)
extract useBindSocial hook
This commit is contained in:
parent
12cf518c88
commit
ce4d6daad2
4 changed files with 76 additions and 46 deletions
|
@ -21,13 +21,13 @@ jest.mock('@/apis/social', () => ({
|
||||||
|
|
||||||
describe('SocialCreateAccount', () => {
|
describe('SocialCreateAccount', () => {
|
||||||
it('should match snapshot', () => {
|
it('should match snapshot', () => {
|
||||||
const { queryByText } = render(<SocialCreateAccount connector="github" />);
|
const { queryByText } = render(<SocialCreateAccount connectorId="github" />);
|
||||||
expect(queryByText('description.social_create_account')).not.toBeNull();
|
expect(queryByText('description.social_create_account')).not.toBeNull();
|
||||||
expect(queryByText('description.social_bind_account')).not.toBeNull();
|
expect(queryByText('description.social_bind_account')).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should redirect to sign in page when click sign-in button', () => {
|
it('should redirect to sign in page when click sign-in button', () => {
|
||||||
const { getByText } = render(<SocialCreateAccount connector="github" />);
|
const { getByText } = render(<SocialCreateAccount connectorId="github" />);
|
||||||
|
|
||||||
const signInButton = getByText('action.sign_in');
|
const signInButton = getByText('action.sign_in');
|
||||||
fireEvent.click(signInButton);
|
fireEvent.click(signInButton);
|
||||||
|
@ -35,7 +35,7 @@ describe('SocialCreateAccount', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call registerWithSocial when click create button', async () => {
|
it('should call registerWithSocial when click create button', async () => {
|
||||||
const { getByText } = renderWithPageContext(<SocialCreateAccount connector="github" />);
|
const { getByText } = renderWithPageContext(<SocialCreateAccount connectorId="github" />);
|
||||||
const createButton = getByText('action.create');
|
const createButton = getByText('action.create');
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
|
@ -46,7 +46,7 @@ describe('SocialCreateAccount', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render bindUser Button when relatedUserInfo found', async () => {
|
it('should render bindUser Button when relatedUserInfo found', async () => {
|
||||||
const { getByText } = renderWithPageContext(<SocialCreateAccount connector="github" />);
|
const { getByText } = renderWithPageContext(<SocialCreateAccount connectorId="github" />);
|
||||||
const bindButton = getByText('action.bind');
|
const bindButton = getByText('action.bind');
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
fireEvent.click(bindButton);
|
fireEvent.click(bindButton);
|
||||||
|
|
|
@ -1,69 +1,49 @@
|
||||||
import { Optional } from '@silverhand/essentials';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useEffect, useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { registerWithSocial, bindSocialRelatedUser } from '@/apis/social';
|
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
import useApi from '@/hooks/use-api';
|
import useBindSocial from '@/hooks/use-bind-social';
|
||||||
|
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
connector: string;
|
connectorId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LocationState = {
|
const SocialCreateAccount = ({ connectorId, className }: Props) => {
|
||||||
relatedUser?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SocialCreateAccount = ({ connector, className }: Props) => {
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const state = useLocation().state as Optional<LocationState>;
|
|
||||||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' });
|
||||||
|
const { relatedUser, registerWithSocial, bindSocialRelatedUser } = useBindSocial();
|
||||||
const { result: registerResult, run: asyncRegisterWithSocial } = useApi(registerWithSocial);
|
|
||||||
const { result: bindUserResult, run: asyncBindSocialRelatedUser } = useApi(bindSocialRelatedUser);
|
|
||||||
|
|
||||||
const createAccountHandler = useCallback(() => {
|
|
||||||
void asyncRegisterWithSocial(connector);
|
|
||||||
}, [asyncRegisterWithSocial, connector]);
|
|
||||||
|
|
||||||
const bindRelatedUserHandler = useCallback(() => {
|
|
||||||
void asyncBindSocialRelatedUser(connector);
|
|
||||||
}, [asyncBindSocialRelatedUser, connector]);
|
|
||||||
|
|
||||||
const signInHandler = useCallback(() => {
|
const signInHandler = useCallback(() => {
|
||||||
// TODO: redirect to desired sign-in page
|
// TODO: redirect to desired sign-in page
|
||||||
navigate('/sign-in/username/' + connector);
|
navigate('/sign-in/username/' + connectorId);
|
||||||
}, [connector, navigate]);
|
}, [connectorId, navigate]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (registerResult?.redirectTo) {
|
|
||||||
window.location.assign(registerResult.redirectTo);
|
|
||||||
}
|
|
||||||
}, [registerResult]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (bindUserResult?.redirectTo) {
|
|
||||||
window.location.assign(bindUserResult.redirectTo);
|
|
||||||
}
|
|
||||||
}, [bindUserResult]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(styles.container, className)}>
|
<div className={classNames(styles.container, className)}>
|
||||||
{state?.relatedUser && (
|
{relatedUser && (
|
||||||
<>
|
<>
|
||||||
<div className={styles.desc}>{t('description.social_bind_with_existing')}</div>
|
<div className={styles.desc}>{t('description.social_bind_with_existing')}</div>
|
||||||
<Button onClick={bindRelatedUserHandler}>
|
<Button
|
||||||
{t('action.bind', { address: state.relatedUser })}
|
onClick={() => {
|
||||||
|
bindSocialRelatedUser(connectorId);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('action.bind', { address: relatedUser })}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className={styles.desc}>{t('description.social_create_account')}</div>
|
<div className={styles.desc}>{t('description.social_create_account')}</div>
|
||||||
<Button type={state?.relatedUser ? 'secondary' : 'primary'} onClick={createAccountHandler}>
|
<Button
|
||||||
|
type={relatedUser ? 'secondary' : 'primary'}
|
||||||
|
onClick={() => {
|
||||||
|
registerWithSocial(connectorId);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{t('action.create')}
|
{t('action.create')}
|
||||||
</Button>
|
</Button>
|
||||||
<div className={styles.desc}>{t('description.social_bind_account')}</div>
|
<div className={styles.desc}>{t('description.social_bind_account')}</div>
|
||||||
|
|
50
packages/ui/src/hooks/use-bind-social.ts
Normal file
50
packages/ui/src/hooks/use-bind-social.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import { Optional } from '@silverhand/essentials';
|
||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { registerWithSocial, bindSocialRelatedUser } from '@/apis/social';
|
||||||
|
import useApi from '@/hooks/use-api';
|
||||||
|
|
||||||
|
type LocationState = {
|
||||||
|
relatedUser?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useBindSocial = () => {
|
||||||
|
const state = useLocation().state as Optional<LocationState>;
|
||||||
|
const { result: registerResult, run: asyncRegisterWithSocial } = useApi(registerWithSocial);
|
||||||
|
const { result: bindUserResult, run: asyncBindSocialRelatedUser } = useApi(bindSocialRelatedUser);
|
||||||
|
|
||||||
|
const createAccountHandler = useCallback(
|
||||||
|
(connectorId: string) => {
|
||||||
|
void asyncRegisterWithSocial(connectorId);
|
||||||
|
},
|
||||||
|
[asyncRegisterWithSocial]
|
||||||
|
);
|
||||||
|
|
||||||
|
const bindRelatedUserHandler = useCallback(
|
||||||
|
(connectorId) => {
|
||||||
|
void asyncBindSocialRelatedUser(connectorId);
|
||||||
|
},
|
||||||
|
[asyncBindSocialRelatedUser]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (registerResult?.redirectTo) {
|
||||||
|
window.location.assign(registerResult.redirectTo);
|
||||||
|
}
|
||||||
|
}, [registerResult]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (bindUserResult?.redirectTo) {
|
||||||
|
window.location.assign(bindUserResult.redirectTo);
|
||||||
|
}
|
||||||
|
}, [bindUserResult]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
relatedUser: state?.relatedUser,
|
||||||
|
registerWithSocial: createAccountHandler,
|
||||||
|
bindSocialRelatedUser: bindRelatedUserHandler,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useBindSocial;
|
|
@ -29,7 +29,7 @@ const SocialRegister = () => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<NavBar title={t('description.bind_account_title')} />
|
<NavBar title={t('description.bind_account_title')} />
|
||||||
<SocialCreateAccount connector={connector} />
|
<SocialCreateAccount connectorId={connector} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue