-
-
Notifications
You must be signed in to change notification settings - Fork 466
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ui): add social sign-in binding page (#664)
* feat(ui): add social sign-in binding page add social sing-in binding page * feat(ui): temp redirect to the username sign-in page temp redirect to the username sign-in page * fix(ui): fix style missing bug fix style missing bug
- Loading branch information
Showing
13 changed files
with
292 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
packages/ui/src/containers/SocialCreateAccount/index.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
@use '@/scss/underscore' as _; | ||
|
||
|
||
.container { | ||
width: 100%; | ||
max-width: 360px; | ||
margin: 0 auto; | ||
@include _.flex-column; | ||
|
||
> * { | ||
width: 100%; | ||
} | ||
} | ||
|
||
.desc { | ||
@include _.text-hint; | ||
margin-bottom: _.unit(2); | ||
|
||
&:not(:first-child) { | ||
margin-top: _.unit(8); | ||
} | ||
} | ||
|
56 changes: 56 additions & 0 deletions
56
packages/ui/src/containers/SocialCreateAccount/index.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { render, fireEvent, waitFor } from '@testing-library/react'; | ||
import React from 'react'; | ||
|
||
import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; | ||
import { registerWithSocial, bindSocialRelatedUser } from '@/apis/social'; | ||
|
||
import SocialCreateAccount from '.'; | ||
|
||
const mockNavigate = jest.fn(); | ||
|
||
jest.mock('react-router-dom', () => ({ | ||
...jest.requireActual('react-router-dom'), | ||
useNavigate: () => mockNavigate, | ||
useLocation: () => ({ state: { relatedUser: '[email protected]' } }), | ||
})); | ||
|
||
jest.mock('@/apis/social', () => ({ | ||
registerWithSocial: jest.fn(async () => Promise.resolve()), | ||
bindSocialRelatedUser: jest.fn(async () => Promise.resolve()), | ||
})); | ||
|
||
describe('SocialCreateAccount', () => { | ||
it('should match snapshot', () => { | ||
const { queryByText } = render(<SocialCreateAccount connector="github" />); | ||
expect(queryByText('description.social_create_account')).not.toBeNull(); | ||
expect(queryByText('description.social_bind_account')).not.toBeNull(); | ||
}); | ||
|
||
it('should redirect to sign in page when click sign-in button', () => { | ||
const { getByText } = render(<SocialCreateAccount connector="github" />); | ||
|
||
const signInButton = getByText('action.sign_in'); | ||
fireEvent.click(signInButton); | ||
expect(mockNavigate).toBeCalledWith('/sign-in/username/github'); | ||
}); | ||
|
||
it('should call registerWithSocial when click create button', async () => { | ||
const { getByText } = renderWithPageContext(<SocialCreateAccount connector="github" />); | ||
const createButton = getByText('action.create'); | ||
|
||
await waitFor(() => { | ||
fireEvent.click(createButton); | ||
}); | ||
|
||
expect(registerWithSocial).toBeCalledWith('github'); | ||
}); | ||
|
||
it('should render bindUser Button when relatedUserInfo found', async () => { | ||
const { getByText } = renderWithPageContext(<SocialCreateAccount connector="github" />); | ||
const bindButton = getByText('action.bind'); | ||
await waitFor(() => { | ||
fireEvent.click(bindButton); | ||
}); | ||
expect(bindSocialRelatedUser).toBeCalledWith('github'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { Optional } from '@silverhand/essentials'; | ||
import classNames from 'classnames'; | ||
import React, { useEffect, useCallback } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { useNavigate, useLocation } from 'react-router-dom'; | ||
|
||
import { registerWithSocial, bindSocialRelatedUser } from '@/apis/social'; | ||
import Button from '@/components/Button'; | ||
import useApi from '@/hooks/use-api'; | ||
|
||
import * as styles from './index.module.scss'; | ||
|
||
type Props = { | ||
className?: string; | ||
connector: string; | ||
}; | ||
|
||
type LocationState = { | ||
relatedUser?: string; | ||
}; | ||
|
||
const SocialCreateAccount = ({ connector, className }: Props) => { | ||
const navigate = useNavigate(); | ||
const state = useLocation().state as Optional<LocationState>; | ||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' }); | ||
|
||
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(() => { | ||
// TODO: redirect to desired sign-in page | ||
navigate('/sign-in/username/' + connector); | ||
}, [connector, navigate]); | ||
|
||
useEffect(() => { | ||
if (registerResult?.redirectTo) { | ||
window.location.assign(registerResult.redirectTo); | ||
} | ||
}, [registerResult]); | ||
|
||
useEffect(() => { | ||
if (bindUserResult?.redirectTo) { | ||
window.location.assign(bindUserResult.redirectTo); | ||
} | ||
}, [bindUserResult]); | ||
|
||
return ( | ||
<div className={classNames(styles.container, className)}> | ||
{state?.relatedUser && ( | ||
<> | ||
<div className={styles.desc}>{t('description.social_bind_with_existing')}</div> | ||
<Button onClick={bindRelatedUserHandler}> | ||
{t('action.bind', { address: state.relatedUser })} | ||
</Button> | ||
</> | ||
)} | ||
<div className={styles.desc}>{t('description.social_create_account')}</div> | ||
<Button type={state?.relatedUser ? 'secondary' : 'primary'} onClick={createAccountHandler}> | ||
{t('action.create')} | ||
</Button> | ||
<div className={styles.desc}>{t('description.social_bind_account')}</div> | ||
<Button type="secondary" onClick={signInHandler}> | ||
{t('action.sign_in')} | ||
</Button> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SocialCreateAccount; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
@use '@/scss/underscore' as _; | ||
|
||
.wrapper { | ||
position: relative; | ||
padding: _.unit(8) _.unit(5); | ||
@include _.flex-column; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { render } from '@testing-library/react'; | ||
import React from 'react'; | ||
import { MemoryRouter, Route, Routes } from 'react-router-dom'; | ||
|
||
import SocialRegister from '.'; | ||
|
||
const mockNavigate = jest.fn(); | ||
|
||
jest.mock('react-router-dom', () => ({ | ||
...jest.requireActual('react-router-dom'), | ||
useNavigate: () => mockNavigate, | ||
})); | ||
|
||
describe('SocialRegister', () => { | ||
it('render null and redirect if no connector found', () => { | ||
render( | ||
<MemoryRouter initialEntries={['/social-register']}> | ||
<Routes> | ||
<Route path="/social-register" element={<SocialRegister />} /> | ||
</Routes> | ||
</MemoryRouter> | ||
); | ||
expect(mockNavigate).toBeCalledWith('/404'); | ||
}); | ||
|
||
it('render with connection', () => { | ||
const { queryByText } = render( | ||
<MemoryRouter initialEntries={['/social-register/github']}> | ||
<Routes> | ||
<Route path="/social-register/:connector" element={<SocialRegister />} /> | ||
</Routes> | ||
</MemoryRouter> | ||
); | ||
expect(queryByText('description.bind_account_title')).not.toBeNull(); | ||
expect(queryByText('description.social_create_account')).not.toBeNull(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React, { useEffect } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { useParams, useNavigate } from 'react-router-dom'; | ||
|
||
import NavBar from '@/components/NavBar'; | ||
import SocialCreateAccount from '@/containers/SocialCreateAccount'; | ||
|
||
import * as styles from './index.module.scss'; | ||
|
||
type Parameters = { | ||
connector: string; | ||
}; | ||
|
||
const SocialRegister = () => { | ||
const { t } = useTranslation(undefined, { keyPrefix: 'main_flow' }); | ||
const { connector } = useParams<Parameters>(); | ||
const navigate = useNavigate(); | ||
|
||
useEffect(() => { | ||
if (!connector) { | ||
navigate('/404'); | ||
} | ||
}, [connector, navigate]); | ||
|
||
if (!connector) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className={styles.wrapper}> | ||
<NavBar title={t('description.bind_account_title')} /> | ||
<SocialCreateAccount connector={connector} /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SocialRegister; |