forked from sombochea/verdaccio-ui
fix: type lint for login
This commit is contained in:
parent
116055c5d1
commit
91e603ef21
@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import { Wrapper, Left, Right, Earth, Flags, Love, Flag, Logo, Inner, ToolTip } from './styles';
|
import { Wrapper, Left, Right, Earth, Flags, Love, Flag, Logo, Inner, ToolTip } from './styles';
|
||||||
import { goToVerdaccioWebsite } from '../../utils/windows';
|
import { goToVerdaccioWebsite } from '../../utils/windows';
|
||||||
|
|
||||||
const renderTooltip = () => (
|
const renderTooltip = (): JSX.Element => (
|
||||||
<ToolTip>
|
<ToolTip>
|
||||||
<Earth name="earth" size="md" />
|
<Earth name="earth" size="md" />
|
||||||
<Flags>
|
<Flags>
|
||||||
@ -22,7 +22,7 @@ const ON_LABEL = 'on';
|
|||||||
const HEARTH_EMOJI = '♥';
|
const HEARTH_EMOJI = '♥';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const renderRight = (version = window.VERDACCIO_VERSION) => {
|
const renderRight = (version = window.VERDACCIO_VERSION): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Right>
|
<Right>
|
||||||
{POWERED_LABEL}
|
{POWERED_LABEL}
|
||||||
@ -32,7 +32,7 @@ const renderRight = (version = window.VERDACCIO_VERSION) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderLeft = () => (
|
const renderLeft = (): JSX.Element => (
|
||||||
<Left>
|
<Left>
|
||||||
{MADEWITH_LABEL}
|
{MADEWITH_LABEL}
|
||||||
<Love>{HEARTH_EMOJI}</Love>
|
<Love>{HEARTH_EMOJI}</Love>
|
||||||
|
@ -67,7 +67,7 @@ const Icon: React.FC<Props> = ({ className, name, size = 'sm', img = false, poin
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const title = capitalize(name);
|
const title = capitalize(name);
|
||||||
return img ? (
|
return img ? (
|
||||||
<ImgWrapper className={className} name={name} pointer={pointer} size={size} title={title} {...props}>
|
<ImgWrapper className={className} pointer={pointer} size={size} title={title} {...props}>
|
||||||
<Img alt={title} src={Icons[name]} />
|
<Img alt={title} src={Icons[name]} />
|
||||||
</ImgWrapper>
|
</ImgWrapper>
|
||||||
) : (
|
) : (
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import styled, { css } from 'react-emotion';
|
import styled, { css } from 'react-emotion';
|
||||||
|
|
||||||
const getSize = (size?: 'md' | 'sm') => {
|
const getSize = (size: 'md' | 'sm' | string): string => {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 'md':
|
case 'md':
|
||||||
return `
|
return `
|
||||||
@ -15,7 +15,7 @@ const getSize = (size?: 'md' | 'sm') => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const commonStyle = ({ size = 'sm', pointer, modifiers }: any) => css`
|
const commonStyle = ({ size = 'sm' as 'md' | 'sm' | string, pointer, modifiers = null }): string => css`
|
||||||
&& {
|
&& {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: ${pointer ? 'pointer' : 'default'};
|
cursor: ${pointer ? 'pointer' : 'default'};
|
||||||
|
@ -3,7 +3,7 @@ import ListItemText from '@material-ui/core/ListItemText';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { DetailContextConsumer } from '../../pages/version/Version';
|
import { DetailContextConsumer, VersionPageConsumerProps } from '../../pages/version/Version';
|
||||||
import CopyToClipBoard from '../CopyToClipBoard';
|
import CopyToClipBoard from '../CopyToClipBoard';
|
||||||
|
|
||||||
// logos of package managers
|
// logos of package managers
|
||||||
@ -14,17 +14,17 @@ import yarn from './img/yarn.svg';
|
|||||||
import { Heading, InstallItem, PackageMangerAvatar } from './styles';
|
import { Heading, InstallItem, PackageMangerAvatar } from './styles';
|
||||||
|
|
||||||
class Install extends Component {
|
class Install extends Component {
|
||||||
public render() {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<DetailContextConsumer>
|
<DetailContextConsumer>
|
||||||
{(context: any) => {
|
{(context: Partial<VersionPageConsumerProps>) => {
|
||||||
return context && context.packageName && this.renderCopyCLI(context);
|
return context && context.packageName && this.renderCopyCLI(context);
|
||||||
}}
|
}}
|
||||||
</DetailContextConsumer>
|
</DetailContextConsumer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderCopyCLI = ({ packageName }: { packageName: string }) => {
|
public renderCopyCLI = ({ packageName = '' }: Partial<VersionPageConsumerProps>) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List subheader={<Heading variant={'subheading'}>{'Installation'}</Heading>}>{this.renderListItems(packageName)}</List>
|
<List subheader={<Heading variant={'subheading'}>{'Installation'}</Heading>}>{this.renderListItems(packageName)}</List>
|
||||||
|
@ -89,7 +89,7 @@ describe('<LoginModal />', () => {
|
|||||||
const instance = wrapper.instance();
|
const instance = wrapper.instance();
|
||||||
|
|
||||||
instance.submitCredentials = jest.fn();
|
instance.submitCredentials = jest.fn();
|
||||||
const { validateCredentials, setCredentials, submitCredentials } = instance;
|
const { handleValidateCredentials, setCredentials, submitCredentials } = instance;
|
||||||
|
|
||||||
expect(setCredentials('username', eventUsername)).toBeUndefined();
|
expect(setCredentials('username', eventUsername)).toBeUndefined();
|
||||||
expect(wrapper.state('form').username.value).toEqual('xyz');
|
expect(wrapper.state('form').username.value).toEqual('xyz');
|
||||||
@ -97,7 +97,7 @@ describe('<LoginModal />', () => {
|
|||||||
expect(setCredentials('password', eventPassword)).toBeUndefined();
|
expect(setCredentials('password', eventPassword)).toBeUndefined();
|
||||||
expect(wrapper.state('form').password.value).toEqual('1234');
|
expect(wrapper.state('form').password.value).toEqual('1234');
|
||||||
|
|
||||||
validateCredentials(event);
|
handleValidateCredentials(event);
|
||||||
expect(event.preventDefault).toHaveBeenCalled();
|
expect(event.preventDefault).toHaveBeenCalled();
|
||||||
expect(wrapper.state('form').username.pristine).toEqual(false);
|
expect(wrapper.state('form').username.pristine).toEqual(false);
|
||||||
expect(wrapper.state('form').password.pristine).toEqual(false);
|
expect(wrapper.state('form').password.pristine).toEqual(false);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Button from '@material-ui/core/Button';
|
import Button from '@material-ui/core/Button';
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import Dialog from '@material-ui/core/Dialog';
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
@ -15,21 +14,34 @@ import FormHelperText from '@material-ui/core/FormHelperText';
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import classes from './login.scss';
|
import classes from './login.scss';
|
||||||
|
|
||||||
export default class LoginModal extends Component<any, any> {
|
interface FormFields {
|
||||||
static propTypes = {
|
required: boolean;
|
||||||
visibility: PropTypes.bool,
|
pristine: boolean;
|
||||||
error: PropTypes.object,
|
helperText: string;
|
||||||
onCancel: PropTypes.func,
|
value: string;
|
||||||
onSubmit: PropTypes.func,
|
}
|
||||||
};
|
interface FormError {
|
||||||
|
type: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
interface LoginModalProps {
|
||||||
error: {},
|
visibility: boolean;
|
||||||
onCancel: () => {},
|
error: Partial<FormError>;
|
||||||
onSubmit: () => {},
|
onCancel: () => void;
|
||||||
visibility: true,
|
onSubmit: (username: string, password: string) => void;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
interface LoginModalState {
|
||||||
|
form: {
|
||||||
|
username: Partial<FormFields>;
|
||||||
|
password: Partial<FormFields>;
|
||||||
|
};
|
||||||
|
error: FormError;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class LoginModal extends Component<Partial<LoginModalProps>, LoginModalState> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -51,11 +63,28 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public render(): JSX.Element {
|
||||||
|
const { visibility, onCancel, error } = this.props as LoginModalProps;
|
||||||
|
return (
|
||||||
|
<Dialog fullWidth={true} id={'login--form-container'} maxWidth={'xs'} onClose={onCancel} open={visibility}>
|
||||||
|
<form noValidate={true} onSubmit={this.handleValidateCredentials}>
|
||||||
|
<DialogTitle>{'Login'}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
{this.renderLoginError(error)}
|
||||||
|
{this.renderNameField()}
|
||||||
|
{this.renderPasswordField()}
|
||||||
|
</DialogContent>
|
||||||
|
{this.renderActions()}
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set login modal's username and password to current state
|
* set login modal's username and password to current state
|
||||||
* Required to login
|
* Required to login
|
||||||
*/
|
*/
|
||||||
setCredentials = (name, e) => {
|
public setCredentials = (name, e) => {
|
||||||
const { form } = this.state;
|
const { form } = this.state;
|
||||||
this.setState({
|
this.setState({
|
||||||
form: {
|
form: {
|
||||||
@ -69,15 +98,15 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setUsername = event => {
|
public handleUsernameChange = event => {
|
||||||
this.setCredentials('username', event);
|
this.setCredentials('username', event);
|
||||||
};
|
};
|
||||||
|
|
||||||
setPassword = event => {
|
public handlePasswordChange = event => {
|
||||||
this.setCredentials('password', event);
|
this.setCredentials('password', event);
|
||||||
};
|
};
|
||||||
|
|
||||||
validateCredentials = event => {
|
public handleValidateCredentials = event => {
|
||||||
const { form } = this.state;
|
const { form } = this.state;
|
||||||
// prevents default submit behavior
|
// prevents default submit behavior
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -89,7 +118,7 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
...acc,
|
...acc,
|
||||||
...{ [key]: { ...form[key], pristine: false } },
|
...{ [key]: { ...form[key], pristine: false } },
|
||||||
}),
|
}),
|
||||||
{}
|
{ username: {}, password: {} }
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
@ -100,10 +129,14 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
submitCredentials = async () => {
|
public submitCredentials = async () => {
|
||||||
const { form } = this.state;
|
const { form } = this.state;
|
||||||
|
const username = (form.username && form.username.value) || '';
|
||||||
|
const password = (form.password && form.password.value) || '';
|
||||||
const { onSubmit } = this.props;
|
const { onSubmit } = this.props;
|
||||||
await onSubmit(form.username.value, form.password.value);
|
if (onSubmit) {
|
||||||
|
await onSubmit(username, password);
|
||||||
|
}
|
||||||
// let's wait for API response and then set
|
// let's wait for API response and then set
|
||||||
// username and password filed to empty state
|
// username and password filed to empty state
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -112,12 +145,12 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
...acc,
|
...acc,
|
||||||
...{ [key]: { ...form[key], value: '', pristine: true } },
|
...{ [key]: { ...form[key], value: '', pristine: true } },
|
||||||
}),
|
}),
|
||||||
{}
|
{ username: {}, password: {} }
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
renderErrorMessage(title, description) {
|
private renderErrorMessage(title, description): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<div>
|
<div>
|
||||||
@ -128,7 +161,7 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMessage(title, description) {
|
private renderMessage(title, description): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className={classes.loginErrorMsg} id={'client-snackbar'}>
|
<div className={classes.loginErrorMsg} id={'client-snackbar'}>
|
||||||
<ErrorIcon className={classes.loginIcon} />
|
<ErrorIcon className={classes.loginIcon} />
|
||||||
@ -137,37 +170,37 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLoginError({ type, title, description }) {
|
private renderLoginError({ type, title, description }: Partial<FormError>): JSX.Element | false {
|
||||||
return type === 'error' && <SnackbarContent className={classes.loginError} message={this.renderMessage(title, description)} />;
|
return type === 'error' && <SnackbarContent className={classes.loginError} message={this.renderMessage(title, description)} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNameField = () => {
|
private renderNameField = () => {
|
||||||
const {
|
const {
|
||||||
form: { username },
|
form: { username },
|
||||||
} = this.state;
|
} = this.state;
|
||||||
return (
|
return (
|
||||||
<FormControl error={!username.value && !username.pristine} fullWidth={true} required={username.required}>
|
<FormControl error={!username.value && !username.pristine} fullWidth={true} required={username.required}>
|
||||||
<InputLabel htmlFor={'username'}>{'Username'}</InputLabel>
|
<InputLabel htmlFor={'username'}>{'Username'}</InputLabel>
|
||||||
<Input id={'login--form-username'} onChange={this.setUsername} placeholder={'Your username'} value={username.value} />
|
<Input id={'login--form-username'} onChange={this.handleUsernameChange} placeholder={'Your username'} value={username.value} />
|
||||||
{!username.value && !username.pristine && <FormHelperText id={'username-error'}>{username.helperText}</FormHelperText>}
|
{!username.value && !username.pristine && <FormHelperText id={'username-error'}>{username.helperText}</FormHelperText>}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
renderPasswordField = () => {
|
private renderPasswordField = () => {
|
||||||
const {
|
const {
|
||||||
form: { password },
|
form: { password },
|
||||||
} = this.state;
|
} = this.state;
|
||||||
return (
|
return (
|
||||||
<FormControl error={!password.value && !password.pristine} fullWidth={true} required={password.required} style={{ marginTop: '8px' }}>
|
<FormControl error={!password.value && !password.pristine} fullWidth={true} required={password.required} style={{ marginTop: '8px' }}>
|
||||||
<InputLabel htmlFor={'password'}>{'Password'}</InputLabel>
|
<InputLabel htmlFor={'password'}>{'Password'}</InputLabel>
|
||||||
<Input id={'login--form-password'} onChange={this.setPassword} placeholder={'Your strong password'} type={'password'} value={password.value} />
|
<Input id={'login--form-password'} onChange={this.handlePasswordChange} placeholder={'Your strong password'} type={'password'} value={password.value} />
|
||||||
{!password.value && !password.pristine && <FormHelperText id={'password-error'}>{password.helperText}</FormHelperText>}
|
{!password.value && !password.pristine && <FormHelperText id={'password-error'}>{password.helperText}</FormHelperText>}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
renderActions = () => {
|
private renderActions = () => {
|
||||||
const {
|
const {
|
||||||
form: { username, password },
|
form: { username, password },
|
||||||
} = this.state;
|
} = this.state;
|
||||||
@ -183,21 +216,4 @@ export default class LoginModal extends Component<any, any> {
|
|||||||
</DialogActions>
|
</DialogActions>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
|
||||||
const { visibility, onCancel, error } = this.props;
|
|
||||||
return (
|
|
||||||
<Dialog fullWidth={true} id={'login--form-container'} maxWidth={'xs'} onClose={onCancel} open={visibility}>
|
|
||||||
<form noValidate={true} onSubmit={this.validateCredentials}>
|
|
||||||
<DialogTitle>{'Login'}</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
{this.renderLoginError(error)}
|
|
||||||
{this.renderNameField()}
|
|
||||||
{this.renderPasswordField()}
|
|
||||||
</DialogContent>
|
|
||||||
{this.renderActions()}
|
|
||||||
</form>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||||
import styled, { css, Themed } from 'react-emotion';
|
import styled, { css } from 'react-emotion';
|
||||||
|
|
||||||
import colors from '../../utils/styles/colors';
|
import colors from '../../utils/styles/colors';
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ export const Wrapper = styled('div')`
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
${(props): Themed<any, object> =>
|
${props =>
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
props.centered &&
|
props.centered &&
|
||||||
css`
|
css`
|
||||||
|
Loading…
Reference in New Issue
Block a user