refactor: Create workspace page

This commit is contained in:
tiddlygit-test 2021-02-19 00:19:44 +08:00
parent 6114794732
commit 346e963122
30 changed files with 137 additions and 112 deletions

View file

@ -0,0 +1,63 @@
import React from 'react';
import styled from 'styled-components';
import { useTranslation } from 'react-i18next';
import TextField from '@material-ui/core/TextField';
import GitHubLogin from './github-login';
import type { IAuthingUserInfo, IAuthingResponse } from '@services/types';
const GitTokenInput = styled(TextField)``;
export const setGithubToken = async (token: string | undefined): Promise<void> => await window.service.auth.set('github-token', token);
export const getGithubToken = async (): Promise<string | undefined> => await window.service.auth.get('github-token');
export function GithubTokenForm(props: {
accessTokenSetter: (token?: string) => void;
userInfoSetter: (info?: IAuthingUserInfo) => void;
accessToken: string;
children: JSX.Element;
}): JSX.Element {
const { accessToken, children } = props;
const { t } = useTranslation();
return (
<>
<GitHubLogin
onSuccess={(response: IAuthingResponse) => {
const accessTokenToSet = response?.userInfo?.thirdPartyIdentity?.accessToken;
const authDataString = response?.userInfo?.oauth;
if (accessTokenToSet !== undefined) {
props.accessTokenSetter(accessTokenToSet);
}
// all data we need
if (accessTokenToSet !== undefined && authDataString !== undefined) {
const authData = JSON.parse(authDataString);
const nextUserInfo = {
...response.userInfo,
...authData,
...response.userInfo.thirdPartyIdentity,
};
delete nextUserInfo.oauth;
delete nextUserInfo.thirdPartyIdentity;
props.userInfoSetter(nextUserInfo as IAuthingUserInfo);
}
}}
// eslint-disable-next-line unicorn/no-null
onLogout={(response: any) => props.accessTokenSetter()}
onFailure={(response: any) => {
props.accessTokenSetter();
props.userInfoSetter();
}}
/>
<GitTokenInput
helperText={t('AddWorkspace.GitTokenDescription')}
fullWidth
onChange={(event) => {
props.accessTokenSetter(event.target.value);
}}
value={accessToken ?? ''}
/>
{children}
</>
);
}

View file

@ -0,0 +1,113 @@
/* eslint-disable promise/no-nesting */
import React, { Component } from 'react';
import styled from 'styled-components';
import Button from '@material-ui/core/Button';
import GithubIcon from '@material-ui/icons/GitHub';
import AuthingSSO from '@authing/sso';
import { withTranslation } from 'react-i18next';
import { APP_DOMAIN, APP_ID } from '../../constants/auth';
const SyncToGithubButton = styled(Button)`
white-space: nowrap;
width: 100%;
`;
interface Props {
t: (x: string) => string;
onRequest: Function;
onSuccess: Function;
onLogout: Function;
onFailure: Function;
}
interface State {
isLogin: boolean;
}
class GitHubLogin extends Component<Props, State> {
static defaultProps = {
onRequest: () => {},
onSuccess: () => {},
onLogout: () => {},
onFailure: () => {},
};
auth: typeof AuthingSSO;
intervalHandel: IntervalID;
constructor(props: Props) {
super(props);
this.state = {
isLogin: false,
};
this.auth = new AuthingSSO({
appId: APP_ID,
appDomain: APP_DOMAIN,
redirectUrl: 'http://localhost:3000',
});
this.updateLoginState();
}
async isLogin(): boolean {
const { onSuccess, onLogout } = this.props;
const { session, ...rest } = await this.auth.trackSession();
const isLogin = session !== null && session !== undefined;
if (isLogin) {
onSuccess(rest);
} else {
onLogout();
}
return isLogin;
}
updateLoginState(): void {
this.intervalHandel = setInterval(() => {
// eslint-disable-next-line promise/catch-or-return, promise/always-return
this.isLogin().then((isLogin) => {
this.setState({ isLogin });
clearInterval(this.intervalHandel);
});
}, 500);
}
render(): JSX.Element {
const { onRequest, onLogout, onFailure, t } = this.props;
const { isLogin } = this.state;
return isLogin ? (
<SyncToGithubButton
onClick={async () => {
const { code, message } = await this.auth.logout();
await window.service.window.clearStorageData();
if (code === 200) {
this.setState({ isLogin: false });
this.updateLoginState();
onLogout();
} else {
console.error(message);
}
}}
color="secondary"
endIcon={<GithubIcon />}>
{t('AddWorkspace.LogoutGithubAccount')}
</SyncToGithubButton>
) : (
<SyncToGithubButton
onClick={() => {
// clear token first, otherwise github login window won't give us a chance to see the form
// void this.auth.logout();
// window.remote.clearStorageData();
try {
onRequest();
this.auth.login();
} catch (error) {
onFailure(error);
}
}}
color="secondary"
endIcon={<GithubIcon />}>
{t('AddWorkspace.LoginGithubAccount')}
</SyncToGithubButton>
);
}
}
export default withTranslation()(GitHubLogin);

View file

@ -0,0 +1,57 @@
import React from 'react';
import Menu from '@material-ui/core/Menu';
interface Props {
buttonElement: React.ReactElement;
id: string;
}
type State = any;
class StatedMenu extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
anchorEl: undefined,
open: false,
};
this.handleClick = this.handleClick.bind(this);
this.handleRequestClose = this.handleRequestClose.bind(this);
}
handleClick(event: any) {
this.setState({ open: true, anchorEl: event.currentTarget });
}
handleRequestClose() {
this.setState({ open: false });
}
render() {
const { buttonElement, children, id } = this.props;
const { anchorEl, open } = this.state;
return (
<>
{React.cloneElement(buttonElement, {
'aria-owns': id,
'aria-haspopup': true,
onClick: this.handleClick,
})}
<Menu id={id} anchorEl={anchorEl} open={open} onClose={this.handleRequestClose} anchorOrigin={{ vertical: 'top', horizontal: 'center' }}>
{React.Children.map(
children,
(child) =>
child &&
// @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call.
React.cloneElement(child, {
onClick: () => {
if ((child as any).props.onClick) {
(child as any).props.onClick();
}
this.handleRequestClose();
},
}),
)}
</Menu>
</>
);
}
}
export default StatedMenu;