More elements migrated to typescript

This commit is contained in:
Alejandro Celaya 2020-08-22 19:03:25 +02:00
parent 62df46d648
commit 2eba607874
9 changed files with 47 additions and 45 deletions

View file

@ -1,23 +1,23 @@
import React from 'react'; import React, { ChangeEvent, FC } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { identity } from 'ramda';
export const basePropTypes = { export interface BooleanControlProps {
checked: PropTypes.bool.isRequired, checked?: boolean;
onChange: PropTypes.func.isRequired, onChange?: (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void;
children: PropTypes.oneOfType([ PropTypes.string, PropTypes.node ]), className?: string;
className: PropTypes.string, }
};
const propTypes = { interface BooleanControlWithTypeProps extends BooleanControlProps {
...basePropTypes, type: 'switch' | 'checkbox';
type: PropTypes.oneOf([ 'switch', 'checkbox' ]).isRequired, }
};
const BooleanControl = ({ checked, onChange, className, children, type }) => { const BooleanControl: FC<BooleanControlWithTypeProps> = (
{ checked = false, onChange = identity, className, children, type },
) => {
const id = uuid(); const id = uuid();
const onChecked = (e) => onChange(e.target.checked, e); const onChecked = (e: ChangeEvent<HTMLInputElement>) => onChange(e.target.checked, e);
const typeClasses = { const typeClasses = {
'custom-switch': type === 'switch', 'custom-switch': type === 'switch',
'custom-checkbox': type === 'checkbox', 'custom-checkbox': type === 'checkbox',
@ -31,6 +31,4 @@ const BooleanControl = ({ checked, onChange, className, children, type }) => {
); );
}; };
BooleanControl.propTypes = propTypes;
export default BooleanControl; export default BooleanControl;

View file

@ -1,8 +0,0 @@
import React from 'react';
import BooleanControl, { basePropTypes } from './BooleanControl';
const Checkbox = (props) => <BooleanControl type="checkbox" {...props} />;
Checkbox.propTypes = basePropTypes;
export default Checkbox;

6
src/utils/Checkbox.tsx Normal file
View file

@ -0,0 +1,6 @@
import React, { FC } from 'react';
import BooleanControl, { BooleanControlProps } from './BooleanControl';
const Checkbox: FC<BooleanControlProps> = (props) => <BooleanControl type="checkbox" {...props} />;
export default Checkbox;

View file

@ -1,8 +0,0 @@
import React from 'react';
import BooleanControl, { basePropTypes } from './BooleanControl';
const ToggleSwitch = (props) => <BooleanControl type="switch" {...props} />;
ToggleSwitch.propTypes = basePropTypes;
export default ToggleSwitch;

View file

@ -0,0 +1,6 @@
import React, { FC } from 'react';
import BooleanControl, { BooleanControlProps } from './BooleanControl';
const ToggleSwitch: FC<BooleanControlProps> = (props) => <BooleanControl type="switch" {...props} />;
export default ToggleSwitch;

View file

@ -1,6 +1,6 @@
import bowser from 'bowser'; import bowser from 'bowser';
import { zipObj } from 'ramda'; import { zipObj } from 'ramda';
import { hasValue } from '../utils'; import { Empty, hasValue } from '../utils';
const DEFAULT = 'Others'; const DEFAULT = 'Others';
const BROWSERS_WHITELIST = [ const BROWSERS_WHITELIST = [
@ -17,17 +17,22 @@ const BROWSERS_WHITELIST = [
'WeChat', 'WeChat',
]; ];
export const parseUserAgent = (userAgent) => { interface UserAgent {
browser: string;
os: string;
}
export const parseUserAgent = (userAgent: string | Empty): UserAgent => {
if (!hasValue(userAgent)) { if (!hasValue(userAgent)) {
return { browser: DEFAULT, os: DEFAULT }; return { browser: DEFAULT, os: DEFAULT };
} }
const { browser: { name: browser }, os: { name: os } } = bowser.parse(userAgent); const { browser: { name: browser }, os: { name: os } } = bowser.parse(userAgent);
return { os: os || DEFAULT, browser: browser && BROWSERS_WHITELIST.includes(browser) ? browser : DEFAULT }; return { os: os ?? DEFAULT, browser: browser && BROWSERS_WHITELIST.includes(browser) ? browser : DEFAULT };
}; };
export const extractDomain = (url) => { export const extractDomain = (url: string | Empty): string => {
if (!hasValue(url)) { if (!hasValue(url)) {
return 'Direct'; return 'Direct';
} }
@ -37,4 +42,5 @@ export const extractDomain = (url) => {
return domain.split(':')[0]; return domain.split(':')[0];
}; };
export const fillTheGaps = (stats, labels) => Object.values({ ...zipObj(labels, labels.map(() => 0)), ...stats }); export const fillTheGaps = (stats: Record<string, number>, labels: string[]): number[] =>
Object.values({ ...zipObj(labels, labels.map(() => 0)), ...stats });

View file

@ -2,7 +2,7 @@ import { isEmpty, isNil, range } from 'ramda';
export type OrderDir = 'ASC' | 'DESC' | undefined; export type OrderDir = 'ASC' | 'DESC' | undefined;
export const determineOrderDir = (currentField: string, newField: string, currentOrderDir: OrderDir): OrderDir => { export const determineOrderDir = (currentField: string, newField: string, currentOrderDir?: OrderDir): OrderDir => {
if (currentField !== newField) { if (currentField !== newField) {
return 'ASC'; return 'ASC';
} }

View file

@ -1,17 +1,19 @@
import React from 'react'; import React, { ChangeEvent, PropsWithChildren } from 'react';
import { mount } from 'enzyme'; import { mount, ReactWrapper } from 'enzyme';
import { Mock } from 'ts-mockery';
import Checkbox from '../../src/utils/Checkbox'; import Checkbox from '../../src/utils/Checkbox';
import { BooleanControlProps } from '../../src/utils/BooleanControl';
describe('<Checkbox />', () => { describe('<Checkbox />', () => {
let wrapped; let wrapped: ReactWrapper;
const createComponent = (props = {}) => { const createComponent = (props: PropsWithChildren<BooleanControlProps> = {}) => {
wrapped = mount(<Checkbox {...props} />); wrapped = mount(<Checkbox {...props} />);
return wrapped; return wrapped;
}; };
afterEach(() => wrapped && wrapped.unmount()); afterEach(() => wrapped?.unmount());
it('includes extra class names when provided', () => { it('includes extra class names when provided', () => {
const classNames = [ 'foo', 'bar', 'baz' ]; const classNames = [ 'foo', 'bar', 'baz' ];
@ -55,11 +57,11 @@ describe('<Checkbox />', () => {
it('changes checked status on input change', () => { it('changes checked status on input change', () => {
const onChange = jest.fn(); const onChange = jest.fn();
const e = { target: { checked: false } }; const e = Mock.of<ChangeEvent<HTMLInputElement>>({ target: { checked: false } });
const wrapped = createComponent({ checked: true, onChange }); const wrapped = createComponent({ checked: true, onChange });
const input = wrapped.find('input'); const input = wrapped.find('input');
input.prop('onChange')(e); (input.prop('onChange') as Function)(e);
expect(onChange).toHaveBeenCalledWith(false, e); expect(onChange).toHaveBeenCalledWith(false, e);
}); });