diff --git a/src/utils/BooleanControl.js b/src/utils/BooleanControl.tsx similarity index 50% rename from src/utils/BooleanControl.js rename to src/utils/BooleanControl.tsx index 3daa7d9f..acf46c93 100644 --- a/src/utils/BooleanControl.js +++ b/src/utils/BooleanControl.tsx @@ -1,23 +1,23 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React, { ChangeEvent, FC } from 'react'; import classNames from 'classnames'; import { v4 as uuid } from 'uuid'; +import { identity } from 'ramda'; -export const basePropTypes = { - checked: PropTypes.bool.isRequired, - onChange: PropTypes.func.isRequired, - children: PropTypes.oneOfType([ PropTypes.string, PropTypes.node ]), - className: PropTypes.string, -}; +export interface BooleanControlProps { + checked?: boolean; + onChange?: (checked: boolean, e: ChangeEvent) => void; + className?: string; +} -const propTypes = { - ...basePropTypes, - type: PropTypes.oneOf([ 'switch', 'checkbox' ]).isRequired, -}; +interface BooleanControlWithTypeProps extends BooleanControlProps { + type: 'switch' | 'checkbox'; +} -const BooleanControl = ({ checked, onChange, className, children, type }) => { +const BooleanControl: FC = ( + { checked = false, onChange = identity, className, children, type }, +) => { const id = uuid(); - const onChecked = (e) => onChange(e.target.checked, e); + const onChecked = (e: ChangeEvent) => onChange(e.target.checked, e); const typeClasses = { 'custom-switch': type === 'switch', 'custom-checkbox': type === 'checkbox', @@ -31,6 +31,4 @@ const BooleanControl = ({ checked, onChange, className, children, type }) => { ); }; -BooleanControl.propTypes = propTypes; - export default BooleanControl; diff --git a/src/utils/Checkbox.js b/src/utils/Checkbox.js deleted file mode 100644 index b253bdfc..00000000 --- a/src/utils/Checkbox.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import BooleanControl, { basePropTypes } from './BooleanControl'; - -const Checkbox = (props) => ; - -Checkbox.propTypes = basePropTypes; - -export default Checkbox; diff --git a/src/utils/Checkbox.tsx b/src/utils/Checkbox.tsx new file mode 100644 index 00000000..56bc1181 --- /dev/null +++ b/src/utils/Checkbox.tsx @@ -0,0 +1,6 @@ +import React, { FC } from 'react'; +import BooleanControl, { BooleanControlProps } from './BooleanControl'; + +const Checkbox: FC = (props) => ; + +export default Checkbox; diff --git a/src/utils/ToggleSwitch.js b/src/utils/ToggleSwitch.js deleted file mode 100644 index 8f45e96f..00000000 --- a/src/utils/ToggleSwitch.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import BooleanControl, { basePropTypes } from './BooleanControl'; - -const ToggleSwitch = (props) => ; - -ToggleSwitch.propTypes = basePropTypes; - -export default ToggleSwitch; diff --git a/src/utils/ToggleSwitch.tsx b/src/utils/ToggleSwitch.tsx new file mode 100644 index 00000000..3427b143 --- /dev/null +++ b/src/utils/ToggleSwitch.tsx @@ -0,0 +1,6 @@ +import React, { FC } from 'react'; +import BooleanControl, { BooleanControlProps } from './BooleanControl'; + +const ToggleSwitch: FC = (props) => ; + +export default ToggleSwitch; diff --git a/src/utils/helpers/visits.js b/src/utils/helpers/visits.ts similarity index 59% rename from src/utils/helpers/visits.js rename to src/utils/helpers/visits.ts index 51d898f4..4bd0ab49 100644 --- a/src/utils/helpers/visits.js +++ b/src/utils/helpers/visits.ts @@ -1,6 +1,6 @@ import bowser from 'bowser'; import { zipObj } from 'ramda'; -import { hasValue } from '../utils'; +import { Empty, hasValue } from '../utils'; const DEFAULT = 'Others'; const BROWSERS_WHITELIST = [ @@ -17,17 +17,22 @@ const BROWSERS_WHITELIST = [ 'WeChat', ]; -export const parseUserAgent = (userAgent) => { +interface UserAgent { + browser: string; + os: string; +} + +export const parseUserAgent = (userAgent: string | Empty): UserAgent => { if (!hasValue(userAgent)) { return { browser: DEFAULT, os: DEFAULT }; } 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)) { return 'Direct'; } @@ -37,4 +42,5 @@ export const extractDomain = (url) => { return domain.split(':')[0]; }; -export const fillTheGaps = (stats, labels) => Object.values({ ...zipObj(labels, labels.map(() => 0)), ...stats }); +export const fillTheGaps = (stats: Record, labels: string[]): number[] => + Object.values({ ...zipObj(labels, labels.map(() => 0)), ...stats }); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 3fc26d0f..27521f1e 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -2,7 +2,7 @@ import { isEmpty, isNil, range } from 'ramda'; 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) { return 'ASC'; } diff --git a/test/utils/Checkbox.test.js b/test/utils/Checkbox.test.tsx similarity index 76% rename from test/utils/Checkbox.test.js rename to test/utils/Checkbox.test.tsx index 78c8afec..b923e3f8 100644 --- a/test/utils/Checkbox.test.js +++ b/test/utils/Checkbox.test.tsx @@ -1,17 +1,19 @@ -import React from 'react'; -import { mount } from 'enzyme'; +import React, { ChangeEvent, PropsWithChildren } from 'react'; +import { mount, ReactWrapper } from 'enzyme'; +import { Mock } from 'ts-mockery'; import Checkbox from '../../src/utils/Checkbox'; +import { BooleanControlProps } from '../../src/utils/BooleanControl'; describe('', () => { - let wrapped; + let wrapped: ReactWrapper; - const createComponent = (props = {}) => { + const createComponent = (props: PropsWithChildren = {}) => { wrapped = mount(); return wrapped; }; - afterEach(() => wrapped && wrapped.unmount()); + afterEach(() => wrapped?.unmount()); it('includes extra class names when provided', () => { const classNames = [ 'foo', 'bar', 'baz' ]; @@ -55,11 +57,11 @@ describe('', () => { it('changes checked status on input change', () => { const onChange = jest.fn(); - const e = { target: { checked: false } }; + const e = Mock.of>({ target: { checked: false } }); const wrapped = createComponent({ checked: true, onChange }); const input = wrapped.find('input'); - input.prop('onChange')(e); + (input.prop('onChange') as Function)(e); expect(onChange).toHaveBeenCalledWith(false, e); }); diff --git a/test/utils/utils.test.js b/test/utils/utils.test.ts similarity index 100% rename from test/utils/utils.test.js rename to test/utils/utils.test.ts