fix: type lint for login

This commit is contained in:
Griffithtp 2019-06-23 22:44:53 +01:00
parent 116055c5d1
commit 91e603ef21
7 changed files with 77 additions and 61 deletions

View File

@ -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>

View File

@ -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>
) : ( ) : (

View File

@ -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'};

View File

@ -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>

View File

@ -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);

View File

@ -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>
);
}
} }

View File

@ -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`