From 4b44bb37d9e65e3932041d6cdbeb7e768ed7d8c9 Mon Sep 17 00:00:00 2001 From: Marlon Johnson Date: Fri, 25 Jun 2021 07:23:52 -0700 Subject: [PATCH] feat(client): ts-migrate client/src/components/helpers/** (#42593) * refactor(client): convert toggle-button to TypeScript * chore: rename Space to tsx * refactor(client): convert space to TypeScript * chore: rename SlimWidthRow to tsx * refactor(client): slim-width-row to TypeScript * chore: rename SkeletonSprite to ts * fix: fixed typos and resolved paths * chore: resolve path inconsistencies * refactor(client): skelton-sprite to TypeScript * chore: rename loader.test to tsx * chore: add types for react-spinkit * refactor(client): loader to TypeScript * refactor(client): link to TypeScript * refactor(client): image-loader to TypeScript * refactor(client): full-width-row to TypeScript * refactor(client): current-challenge-link to TypeScript * refactor(client): button to TypeScript * refactor(client): border-color-picker to TypeScript * refactor(client): avatar-renderer to TypeScript * chore: changed loadertest(snap) to ts * chore: optional types added and cleaned files * fix: args are now optional * push small updates for Spacer component merge * update snapshot * remove type defs from deps * Revert "remove type defs from deps" This reverts commit 9f58bf35549d12512bb415dbf57891b7753f3c7f. * correctly remove client type deps * final push to remove from deps Co-authored-by: Shaun Hamilton --- .../ShowProfileOrFourOhFour.js | 2 +- .../client-only-routes/ShowUnsubscribed.js | 2 +- client/src/components/Donation/DonateForm.js | 2 +- client/src/components/Footer/index.js | 2 +- client/src/components/Intro/index.js | 2 +- client/src/components/helpers/Spacer.js | 22 -------------- ...ader.test.js.snap => loader.test.tsx.snap} | 0 ...{AvatarRenderer.js => avatar-renderer.tsx} | 27 +++++++++-------- ...rColorPicker.js => border-color-picker.ts} | 5 +++- .../{ButtonSpacer.js => button-spacer.tsx} | 2 +- ...engeLink.js => current-challenge-link.tsx} | 21 ++++++++------ .../{FullWidthRow.js => full-width-row.tsx} | 13 +++++---- .../{ImageLoader.js => image-loader.tsx} | 29 ++++++++++--------- client/src/components/helpers/index.js | 22 +++++++------- .../helpers/{Link.test.js => link.test.tsx} | 10 ++++--- .../components/helpers/{Link.js => link.tsx} | 22 ++++++++------ .../{Loader.test.js => loader.test.tsx} | 2 +- .../helpers/{Loader.js => loader.tsx} | 13 ++++----- ...{SkeletonSprite.js => skeleton-sprite.tsx} | 7 +++-- .../{skeletonStyles.js => skeleton-styles.ts} | 0 .../{SlimWidthRow.js => slim-width-row.tsx} | 12 ++++---- client/src/components/helpers/spacer.tsx | 24 +++++++++++++++ .../{ToggleButton.js => toggle-button.tsx} | 23 ++++++++------- client/src/components/profile/Profile.js | 2 +- .../components/profile/components/Camper.js | 2 +- .../components/profile/components/HeatMap.js | 4 +-- client/src/components/settings/Email.js | 4 +-- client/src/components/settings/Privacy.js | 4 +-- .../src/components/settings/SectionHeader.js | 2 +- .../src/components/settings/ToggleSetting.js | 2 +- client/src/components/settings/Username.js | 2 +- .../Challenges/projects/backend/Show.js | 2 +- .../Challenges/projects/frontend/Show.js | 2 +- client/src/templates/Challenges/video/Show.js | 4 +-- client/src/templates/Introduction/Intro.js | 4 +-- client/tsconfig.json | 15 ++++++++-- 36 files changed, 173 insertions(+), 140 deletions(-) delete mode 100644 client/src/components/helpers/Spacer.js rename client/src/components/helpers/__snapshots__/{Loader.test.js.snap => loader.test.tsx.snap} (100%) rename client/src/components/helpers/{AvatarRenderer.js => avatar-renderer.tsx} (63%) rename client/src/components/helpers/{borderColorPicker.js => border-color-picker.ts} (64%) rename client/src/components/helpers/{ButtonSpacer.js => button-spacer.tsx} (81%) rename client/src/components/helpers/{CurrentChallengeLink.js => current-challenge-link.tsx} (67%) rename client/src/components/helpers/{FullWidthRow.js => full-width-row.tsx} (63%) rename client/src/components/helpers/{ImageLoader.js => image-loader.tsx} (69%) rename client/src/components/helpers/{Link.test.js => link.test.tsx} (64%) rename client/src/components/helpers/{Link.js => link.tsx} (63%) rename client/src/components/helpers/{Loader.test.js => loader.test.tsx} (96%) rename client/src/components/helpers/{Loader.js => loader.tsx} (76%) rename client/src/components/helpers/{SkeletonSprite.js => skeleton-sprite.tsx} (73%) rename client/src/components/helpers/{skeletonStyles.js => skeleton-styles.ts} (100%) rename client/src/components/helpers/{SlimWidthRow.js => slim-width-row.tsx} (63%) create mode 100644 client/src/components/helpers/spacer.tsx rename client/src/components/helpers/{ToggleButton.js => toggle-button.tsx} (82%) diff --git a/client/src/client-only-routes/ShowProfileOrFourOhFour.js b/client/src/client-only-routes/ShowProfileOrFourOhFour.js index 0b6b49cbe0..e164c727e4 100644 --- a/client/src/client-only-routes/ShowProfileOrFourOhFour.js +++ b/client/src/client-only-routes/ShowProfileOrFourOhFour.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { isEmpty } from 'lodash-es'; -import Loader from '../components/helpers/Loader'; +import Loader from '../components/helpers/loader'; import { userByNameSelector, userProfileFetchStateSelector, diff --git a/client/src/client-only-routes/ShowUnsubscribed.js b/client/src/client-only-routes/ShowUnsubscribed.js index 9bfcf9788e..e0cf948ab0 100644 --- a/client/src/client-only-routes/ShowUnsubscribed.js +++ b/client/src/client-only-routes/ShowUnsubscribed.js @@ -5,7 +5,7 @@ import Helmet from 'react-helmet'; import { useTranslation } from 'react-i18next'; import envData from '../../../config/env.json'; -import FullWidthRow from '../components/helpers/FullWidthRow'; +import FullWidthRow from '../components/helpers/full-width-row'; import { Spacer } from '../components/helpers'; const { apiLocation } = envData; diff --git a/client/src/components/Donation/DonateForm.js b/client/src/components/Donation/DonateForm.js index 4b78137620..295bff1365 100644 --- a/client/src/components/Donation/DonateForm.js +++ b/client/src/components/Donation/DonateForm.js @@ -20,7 +20,7 @@ import { defaultDonation, modalDefaultDonation } from '../../../../config/donation-settings'; -import Spacer from '../helpers/Spacer'; +import Spacer from '../helpers/spacer'; import PaypalButton from './PaypalButton'; import DonateCompletion from './DonateCompletion'; import { diff --git a/client/src/components/Footer/index.js b/client/src/components/Footer/index.js index 32ed7e099a..79117fb496 100644 --- a/client/src/components/Footer/index.js +++ b/client/src/components/Footer/index.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; -import Link from '../helpers/Link'; +import Link from '../helpers/link'; import './footer.css'; const propTypes = { diff --git a/client/src/components/Intro/index.js b/client/src/components/Intro/index.js index 69c2934ba5..1eb4bb88df 100644 --- a/client/src/components/Intro/index.js +++ b/client/src/components/Intro/index.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link, Spacer, Loader, FullWidthRow } from '../helpers'; import { randomQuote } from '../../utils/get-words'; -import CurrentChallengeLink from '../helpers/CurrentChallengeLink'; +import CurrentChallengeLink from '../helpers/current-challenge-link'; import IntroDescription from './components/IntroDescription'; import { Trans, useTranslation } from 'react-i18next'; diff --git a/client/src/components/helpers/Spacer.js b/client/src/components/helpers/Spacer.js deleted file mode 100644 index 385b819937..0000000000 --- a/client/src/components/helpers/Spacer.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -const styles = { padding: '15px 0', height: '1px' }; - -const Comp = props =>
; - -const Spacer = ({ size = 1 }) => - size === 1 ? ( - - ) : ( - '#' - .repeat(size) - .split('') - .map((_, i) => ) - ); - -Spacer.propTypes = { - size: PropTypes.number -}; - -export default Spacer; diff --git a/client/src/components/helpers/__snapshots__/Loader.test.js.snap b/client/src/components/helpers/__snapshots__/loader.test.tsx.snap similarity index 100% rename from client/src/components/helpers/__snapshots__/Loader.test.js.snap rename to client/src/components/helpers/__snapshots__/loader.test.tsx.snap diff --git a/client/src/components/helpers/AvatarRenderer.js b/client/src/components/helpers/avatar-renderer.tsx similarity index 63% rename from client/src/components/helpers/AvatarRenderer.js rename to client/src/components/helpers/avatar-renderer.tsx index 21246ee786..ad40555154 100644 --- a/client/src/components/helpers/AvatarRenderer.js +++ b/client/src/components/helpers/avatar-renderer.tsx @@ -1,22 +1,26 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { Image } from '@freecodecamp/react-bootstrap'; import DefaultAvatar from '../../assets/icons/DefaultAvatar'; import { defaultUserImage } from '../../../../config/misc'; -import { borderColorPicker } from '../helpers'; +import { borderColorPicker } from '.'; import { useTranslation } from 'react-i18next'; -const propTypes = { - isDonating: PropTypes.bool, - isTopContributor: PropTypes.bool, - picture: PropTypes.any.isRequired, - userName: PropTypes.string.isRequired -}; +interface AvatarRendererProps { + isDonating?: boolean; + isTopContributor?: boolean; + picture: string; + userName: string; +} -function AvatarRenderer({ picture, userName, isDonating, isTopContributor }) { +function AvatarRenderer({ + picture, + userName, + isDonating, + isTopContributor +}: AvatarRendererProps): JSX.Element { const { t } = useTranslation(); - let borderColor = borderColorPicker(isDonating, isTopContributor); - let isPlaceHolderImage = + const borderColor: string = borderColorPicker(isDonating, isTopContributor); + const isPlaceHolderImage = /example.com|identicon.org/.test(picture) || picture === defaultUserImage; return ( @@ -35,6 +39,5 @@ function AvatarRenderer({ picture, userName, isDonating, isTopContributor }) { ); } -AvatarRenderer.propTypes = propTypes; AvatarRenderer.displayName = 'AvatarRenderer'; export default AvatarRenderer; diff --git a/client/src/components/helpers/borderColorPicker.js b/client/src/components/helpers/border-color-picker.ts similarity index 64% rename from client/src/components/helpers/borderColorPicker.js rename to client/src/components/helpers/border-color-picker.ts index 4a36376509..a225a36136 100644 --- a/client/src/components/helpers/borderColorPicker.js +++ b/client/src/components/helpers/border-color-picker.ts @@ -1,4 +1,7 @@ -export default function borderColorPicker(isDonating, isTopContributor) { +export default function borderColorPicker( + isDonating?: boolean, + isTopContributor?: boolean +): string { if (isDonating && isTopContributor) return 'purple-border'; else if (isTopContributor) return 'blue-border'; else if (isDonating) return 'gold-border'; diff --git a/client/src/components/helpers/ButtonSpacer.js b/client/src/components/helpers/button-spacer.tsx similarity index 81% rename from client/src/components/helpers/ButtonSpacer.js rename to client/src/components/helpers/button-spacer.tsx index 8ac663d857..9813d0b823 100644 --- a/client/src/components/helpers/ButtonSpacer.js +++ b/client/src/components/helpers/button-spacer.tsx @@ -1,6 +1,6 @@ import React from 'react'; -function ButtonSpacer() { +function ButtonSpacer(): JSX.Element { return
; } diff --git a/client/src/components/helpers/CurrentChallengeLink.js b/client/src/components/helpers/current-challenge-link.tsx similarity index 67% rename from client/src/components/helpers/CurrentChallengeLink.js rename to client/src/components/helpers/current-challenge-link.tsx index 279ab66056..176bfcceda 100644 --- a/client/src/components/helpers/CurrentChallengeLink.js +++ b/client/src/components/helpers/current-challenge-link.tsx @@ -1,18 +1,22 @@ import React from 'react'; -import PropTypes from 'prop-types'; import envData from '../../../../config/env.json'; -const { apiLocation } = envData; +interface EnvData { + apiLocation: string; +} + +const { apiLocation } = envData as EnvData; const currentChallengeApi = '/challenges/current-challenge'; -const propTypes = { - children: PropTypes.any, - isLargeBtn: PropTypes.bool -}; - -function CurrentChallengeLink({ children, isLargeBtn }) { +function CurrentChallengeLink({ + children, + isLargeBtn +}: { + children?: JSX.ElementChildrenAttribute; + isLargeBtn?: boolean; +}): JSX.Element { let classNames; if (isLargeBtn) { classNames = 'btn btn-lg btn-primary btn-block'; @@ -27,6 +31,5 @@ function CurrentChallengeLink({ children, isLargeBtn }) { } CurrentChallengeLink.displayName = 'CurrentChallengeLink'; -CurrentChallengeLink.propTypes = propTypes; export default CurrentChallengeLink; diff --git a/client/src/components/helpers/FullWidthRow.js b/client/src/components/helpers/full-width-row.tsx similarity index 63% rename from client/src/components/helpers/FullWidthRow.js rename to client/src/components/helpers/full-width-row.tsx index b55d3fdbf0..f7201a4b39 100644 --- a/client/src/components/helpers/FullWidthRow.js +++ b/client/src/components/helpers/full-width-row.tsx @@ -1,8 +1,13 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { Row, Col } from '@freecodecamp/react-bootstrap'; -function FullWidthRow({ children, className }) { +function FullWidthRow({ + children, + className +}: { + children?: JSX.ElementChildrenAttribute; + className?: string; +}): JSX.Element { return ( @@ -13,9 +18,5 @@ function FullWidthRow({ children, className }) { } FullWidthRow.displayName = 'FullWidthRow'; -FullWidthRow.propTypes = { - children: PropTypes.any, - className: PropTypes.string -}; export default FullWidthRow; diff --git a/client/src/components/helpers/ImageLoader.js b/client/src/components/helpers/image-loader.tsx similarity index 69% rename from client/src/components/helpers/ImageLoader.js rename to client/src/components/helpers/image-loader.tsx index fcc8fe1ddd..53ec38b38f 100644 --- a/client/src/components/helpers/ImageLoader.js +++ b/client/src/components/helpers/image-loader.tsx @@ -1,20 +1,21 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ import React, { useState } from 'react'; import './image-loader.css'; +// @ts-ignore import LazyLoad from 'react-lazy-load'; -import PropTypes from 'prop-types'; -const propTypes = { - alt: PropTypes.string, - className: PropTypes.string, - height: PropTypes.number, - loadedClassName: PropTypes.string, - loadingClassName: PropTypes.string, - offsetVertical: PropTypes.number, - src: PropTypes.string, - style: PropTypes.object, - width: PropTypes.number -}; +interface ImageLoaderProps { + alt?: string; + className?: string; + height?: number; + loadedClassName?: string; + loadingClassName?: string; + offsetVertical?: number; + src?: string; + style?: React.CSSProperties; + width?: number; +} const ImageLoader = ({ className = '', @@ -26,7 +27,7 @@ const ImageLoader = ({ style, width, height -}) => { +}: ImageLoaderProps): JSX.Element => { const [loaded, setLoaded] = useState(false); const fullClassName = `${className} ${ loaded ? loadedClassName : loadingClassName @@ -49,5 +50,5 @@ const ImageLoader = ({ ); }; -ImageLoader.propTypes = propTypes; + export default ImageLoader; diff --git a/client/src/components/helpers/index.js b/client/src/components/helpers/index.js index f59bba1524..a501903a0b 100644 --- a/client/src/components/helpers/index.js +++ b/client/src/components/helpers/index.js @@ -1,11 +1,11 @@ -export { default as ButtonSpacer } from './ButtonSpacer'; -export { default as FullWidthRow } from './FullWidthRow'; -export { default as SlimWidthRow } from './SlimWidthRow'; -export { default as Loader } from './Loader'; -export { default as SkeletonSprite } from './SkeletonSprite'; -export { default as Spacer } from './Spacer'; -export { default as Link } from './Link'; -export { default as CurrentChallengeLink } from './CurrentChallengeLink'; -export { default as ImageLoader } from './ImageLoader'; -export { default as AvatarRenderer } from './AvatarRenderer'; -export { default as borderColorPicker } from './borderColorPicker'; +export { default as ButtonSpacer } from './button-spacer'; +export { default as FullWidthRow } from './full-width-row'; +export { default as SlimWidthRow } from './slim-width-row'; +export { default as Loader } from './loader'; +export { default as SkeletonSprite } from './skeleton-sprite'; +export { default as Spacer } from './spacer'; +export { default as Link } from './link'; +export { default as CurrentChallengeLink } from './current-challenge-link'; +export { default as ImageLoader } from './image-loader'; +export { default as AvatarRenderer } from './avatar-renderer'; +export { default as borderColorPicker } from './border-color-picker'; diff --git a/client/src/components/helpers/Link.test.js b/client/src/components/helpers/link.test.tsx similarity index 64% rename from client/src/components/helpers/Link.test.js rename to client/src/components/helpers/link.test.tsx index 13a2f2cc44..92dc93bde3 100644 --- a/client/src/components/helpers/Link.test.js +++ b/client/src/components/helpers/link.test.tsx @@ -1,13 +1,15 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import renderer, { ReactTestRendererJSON } from 'react-test-renderer'; -import Link from './Link'; +import Link from './link'; describe('', () => { const externalLink = renderer .create() - .toJSON(); - const gatsbyLink = renderer.create().toJSON(); + .toJSON() as ReactTestRendererJSON; + const gatsbyLink = renderer + .create() + .toJSON() as ReactTestRendererJSON; it('renders to the DOM', () => { expect(gatsbyLink).toBeTruthy(); diff --git a/client/src/components/helpers/Link.js b/client/src/components/helpers/link.tsx similarity index 63% rename from client/src/components/helpers/Link.js rename to client/src/components/helpers/link.tsx index f5f9988ae9..91739a7acb 100644 --- a/client/src/components/helpers/Link.js +++ b/client/src/components/helpers/link.tsx @@ -1,15 +1,20 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { Link as GatsbyLink } from 'gatsby'; -const propTypes = { - children: PropTypes.any, - external: PropTypes.bool, - sameTab: PropTypes.bool, - to: PropTypes.string.isRequired -}; +interface LinkProps { + children?: JSX.ElementChildrenAttribute; + external?: boolean; + sameTab?: boolean; + to: string; +} -const Link = ({ children, to, external, sameTab, ...other }) => { +const Link = ({ + children, + to, + external, + sameTab, + ...other +}: LinkProps): JSX.Element => { if (!external && /^\/(?!\/)/.test(to)) { return ( @@ -30,6 +35,5 @@ const Link = ({ children, to, external, sameTab, ...other }) => { ); }; -Link.propTypes = propTypes; export default Link; diff --git a/client/src/components/helpers/Loader.test.js b/client/src/components/helpers/loader.test.tsx similarity index 96% rename from client/src/components/helpers/Loader.test.js rename to client/src/components/helpers/loader.test.tsx index 21bf667513..f57a42b4db 100644 --- a/client/src/components/helpers/Loader.test.js +++ b/client/src/components/helpers/loader.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { render, cleanup } from '@testing-library/react'; -import Loader from './Loader'; +import Loader from './loader'; describe('', () => { afterEach(cleanup); diff --git a/client/src/components/helpers/Loader.js b/client/src/components/helpers/loader.tsx similarity index 76% rename from client/src/components/helpers/Loader.js rename to client/src/components/helpers/loader.tsx index 8bd5a55f3a..e39561e7d9 100644 --- a/client/src/components/helpers/Loader.js +++ b/client/src/components/helpers/loader.tsx @@ -1,13 +1,16 @@ import React, { useState, useEffect } from 'react'; -import PropTypes from 'prop-types'; import Spinner from 'react-spinkit'; import './loader.css'; -function Loader({ fullScreen, timeout }) { +interface LoaderProps { + fullScreen?: boolean; + timeout?: number; +} +function Loader({ fullScreen, timeout }: LoaderProps): JSX.Element { const [showSpinner, setShowSpinner] = useState(!timeout); useEffect(() => { - let timerId; + let timerId: ReturnType; if (!showSpinner) { timerId = setTimeout(() => setShowSpinner(true), timeout); } @@ -21,9 +24,5 @@ function Loader({ fullScreen, timeout }) { } Loader.displayName = 'Loader'; -Loader.propTypes = { - fullScreen: PropTypes.bool, - timeout: PropTypes.number -}; export default Loader; diff --git a/client/src/components/helpers/SkeletonSprite.js b/client/src/components/helpers/skeleton-sprite.tsx similarity index 73% rename from client/src/components/helpers/SkeletonSprite.js rename to client/src/components/helpers/skeleton-sprite.tsx index 7415e8d834..d7401b2d2f 100644 --- a/client/src/components/helpers/SkeletonSprite.js +++ b/client/src/components/helpers/skeleton-sprite.tsx @@ -1,8 +1,11 @@ import React from 'react'; -import styles from './skeletonStyles'; +import styles from './skeleton-styles'; -function SkeletonSprite() { +// TODO: unsure about parameter typing +function SkeletonSprite({}: React.FC< + React.ComponentPropsWithoutRef<'svg'> +>): JSX.Element { return (