From 0fef2a4be64fdcb1fc0250de6e013ce4d3f03cf3 Mon Sep 17 00:00:00 2001 From: The Stedman <46408716+recondesigns@users.noreply.github.com> Date: Mon, 4 Mar 2024 20:57:47 -0600 Subject: [PATCH] Migrate Footer, Heading, DonateSection, HeroBanner, and Modal components to Typescript (#1805) --- components/Footer/{Footer.js => Footer.tsx} | 17 +++++- .../{Footer.test.js => Footer.test.tsx} | 0 ...oter.test.js.snap => Footer.test.tsx.snap} | 0 .../Heading/{Heading.js => Heading.tsx} | 48 ++++++++++----- .../Heading/__stories__/Heading.stories.js | 22 ------- .../Heading/__stories__/Heading.stories.tsx | 18 ++++++ .../{Heading.test.js => Heading.test.tsx} | 0 ...ing.test.js.snap => Heading.test.tsx.snap} | 0 .../{HeroBanner.js => HeroBanner.tsx} | 44 +++++++++----- .../__stories__/HeroBanner.stories.js | 14 ----- .../__stories__/HeroBanner.stories.tsx | 18 ++++++ ...HeroBanner.test.js => HeroBanner.test.tsx} | 0 ....test.js.snap => HeroBanner.test.tsx.snap} | 0 components/Modal/{Modal.js => Modal.tsx} | 57 +++++++++++------- .../{Modal.stories.js => Modal.stories.tsx} | 60 ++++++++----------- .../{Modal.test.js => Modal.test.tsx} | 2 +- ...Modal.test.js.snap => Modal.test.tsx.snap} | 0 .../{DonateSection.js => DonateSection.tsx} | 0 .../__stories__/DonateSection.stories.js | 10 ---- .../__stories__/DonateSection.stories.tsx | 16 +++++ ...Section.test.js => DonateSection.test.tsx} | 0 ...st.js.snap => DonateSection.test.tsx.snap} | 2 - 22 files changed, 192 insertions(+), 136 deletions(-) rename components/Footer/{Footer.js => Footer.tsx} (90%) rename components/Footer/__tests__/{Footer.test.js => Footer.test.tsx} (100%) rename components/Footer/__tests__/__snapshots__/{Footer.test.js.snap => Footer.test.tsx.snap} (100%) rename components/Heading/{Heading.js => Heading.tsx} (56%) delete mode 100644 components/Heading/__stories__/Heading.stories.js create mode 100644 components/Heading/__stories__/Heading.stories.tsx rename components/Heading/__tests__/{Heading.test.js => Heading.test.tsx} (100%) rename components/Heading/__tests__/__snapshots__/{Heading.test.js.snap => Heading.test.tsx.snap} (100%) rename components/HeroBanner/{HeroBanner.js => HeroBanner.tsx} (51%) delete mode 100644 components/HeroBanner/__stories__/HeroBanner.stories.js create mode 100644 components/HeroBanner/__stories__/HeroBanner.stories.tsx rename components/HeroBanner/__tests__/{HeroBanner.test.js => HeroBanner.test.tsx} (100%) rename components/HeroBanner/__tests__/__snapshots__/{HeroBanner.test.js.snap => HeroBanner.test.tsx.snap} (100%) rename components/Modal/{Modal.js => Modal.tsx} (67%) rename components/Modal/__stories__/{Modal.stories.js => Modal.stories.tsx} (71%) rename components/Modal/__tests__/{Modal.test.js => Modal.test.tsx} (93%) rename components/Modal/__tests__/__snapshots__/{Modal.test.js.snap => Modal.test.tsx.snap} (100%) rename components/ReusableSections/DonateSection/{DonateSection.js => DonateSection.tsx} (100%) delete mode 100644 components/ReusableSections/DonateSection/__stories__/DonateSection.stories.js create mode 100644 components/ReusableSections/DonateSection/__stories__/DonateSection.stories.tsx rename components/ReusableSections/DonateSection/__tests__/{DonateSection.test.js => DonateSection.test.tsx} (100%) rename components/ReusableSections/DonateSection/__tests__/__snapshots__/{DonateSection.test.js.snap => DonateSection.test.tsx.snap} (93%) diff --git a/components/Footer/Footer.js b/components/Footer/Footer.tsx similarity index 90% rename from components/Footer/Footer.js rename to components/Footer/Footer.tsx index a21be88f0..ccd316239 100644 --- a/components/Footer/Footer.js +++ b/components/Footer/Footer.tsx @@ -7,11 +7,26 @@ import Image from 'next/image'; import Logo from 'public/static/images/logo.svg'; import styles from './Footer.module.css'; +export type FooterPropsType = { + /** + * Url string applied ot the link. + */ + href: string; + /** + * String applied to the link label. + */ + name: string; + /** + * Only pass analytics event label if you're href is to an external website + */ + analyticsEventLabel?: string; +}; + function Footer() { const currentYear = new Date().getFullYear(); // eslint-disable-next-line react/prop-types - const renderLink = ({ href, name, analyticsEventLabel }) => { + const renderLink = ({ href, name, analyticsEventLabel }: FooterPropsType) => { return (
  • {analyticsEventLabel ? ( diff --git a/components/Footer/__tests__/Footer.test.js b/components/Footer/__tests__/Footer.test.tsx similarity index 100% rename from components/Footer/__tests__/Footer.test.js rename to components/Footer/__tests__/Footer.test.tsx diff --git a/components/Footer/__tests__/__snapshots__/Footer.test.js.snap b/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap similarity index 100% rename from components/Footer/__tests__/__snapshots__/Footer.test.js.snap rename to components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap diff --git a/components/Heading/Heading.js b/components/Heading/Heading.tsx similarity index 56% rename from components/Heading/Heading.js rename to components/Heading/Heading.tsx index 2f0623a65..2c6aa8953 100644 --- a/components/Heading/Heading.js +++ b/components/Heading/Heading.tsx @@ -1,28 +1,46 @@ -import { string, bool, oneOf } from 'prop-types'; import classNames from 'classnames'; import kebabCase from 'lodash/kebabCase'; import ScreenReaderOnly from 'components/ScreenReaderOnly/ScreenReaderOnly'; import LinkIcon from 'static/images/icons/FontAwesome/link-solid.svg'; import styles from './Heading.module.css'; -Heading.propTypes = { - className: string, - hasHashLink: bool, - hasTitleUnderline: bool, - headingLevel: oneOf([1, 2, 3, 4, 5, 6]), - text: string.isRequired, -}; +type HeadingLevelType = 1 | 2 | 3 | 4 | 5 | 6; -Heading.defaultProps = { - className: undefined, - hasHashLink: true, - hasTitleUnderline: false, - headingLevel: 2, +export type HeadingPropsType = { + /** + * Text to be rendered in the heading element. + */ + text: string; + /** + * Applies classnames to the base `figure` element for styling. + */ + className?: string; + /** + * Applies an anchor as the base element if true. + * @default true + */ + hasHashLink?: boolean; + /** + * Displays an optional line under the title. + * @default false + */ + hasTitleUnderline?: boolean; + /** + * Sets the heading level (h1, h2, etc) + * @default 2 + */ + headingLevel?: HeadingLevelType; }; -function Heading({ className, hasHashLink, hasTitleUnderline, headingLevel, text }) { +function Heading({ + className, + hasHashLink = true, + hasTitleUnderline = false, + headingLevel = 2, + text, +}: HeadingPropsType) { const anchorId = `${kebabCase(text)}-link`; - const HeadingElement = `h${headingLevel}`; + const HeadingElement = `h${headingLevel}` as keyof JSX.IntrinsicElements; return (
    diff --git a/components/Heading/__stories__/Heading.stories.js b/components/Heading/__stories__/Heading.stories.js deleted file mode 100644 index fad03c73d..000000000 --- a/components/Heading/__stories__/Heading.stories.js +++ /dev/null @@ -1,22 +0,0 @@ -import Heading from '../Heading'; - -export default { - component: Heading, - title: 'Heading', - argTypes: { - headingLevel: { - control: { - type: 'number', - min: 1, - max: 6, - }, - }, - }, -}; - -const Template = arguments_ => ; - -export const Default = Template.bind({}); -Default.args = { - text: `Heading Text`, -}; diff --git a/components/Heading/__stories__/Heading.stories.tsx b/components/Heading/__stories__/Heading.stories.tsx new file mode 100644 index 000000000..2d105b5ed --- /dev/null +++ b/components/Heading/__stories__/Heading.stories.tsx @@ -0,0 +1,18 @@ +import { Meta, StoryObj } from '@storybook/react'; +import Heading from '../Heading'; + +type HeadingStoryType = StoryObj; + +const meta: Meta = { + title: 'Heading', + component: Heading, + args: { + text: 'Heading text', + }, +}; + +export default meta; + +export const Default: HeadingStoryType = { + render: args => , +}; diff --git a/components/Heading/__tests__/Heading.test.js b/components/Heading/__tests__/Heading.test.tsx similarity index 100% rename from components/Heading/__tests__/Heading.test.js rename to components/Heading/__tests__/Heading.test.tsx diff --git a/components/Heading/__tests__/__snapshots__/Heading.test.js.snap b/components/Heading/__tests__/__snapshots__/Heading.test.tsx.snap similarity index 100% rename from components/Heading/__tests__/__snapshots__/Heading.test.js.snap rename to components/Heading/__tests__/__snapshots__/Heading.test.tsx.snap diff --git a/components/HeroBanner/HeroBanner.js b/components/HeroBanner/HeroBanner.tsx similarity index 51% rename from components/HeroBanner/HeroBanner.js rename to components/HeroBanner/HeroBanner.tsx index a7405b927..37df4ab15 100644 --- a/components/HeroBanner/HeroBanner.js +++ b/components/HeroBanner/HeroBanner.tsx @@ -1,24 +1,38 @@ -import { string, node, bool } from 'prop-types'; import classNames from 'classnames'; import Container from 'components/Container/Container'; import { HERO_BANNER_H1 } from 'common/constants/testIDs'; -HeroBanner.propTypes = { - backgroundImageSource: string, - className: string, - children: node, - isFullViewportHeight: bool, - title: string.isRequired, +export type HeroBannerPropsType = { + /** + * Renders a title for the banner. + */ + title: string; + /** + * Sets the path for an optional background image. + */ + backgroundImageSource?: string; + /** + * Applies classnames to the base `figure` element for styling. + */ + className?: string; + /** + * Content to be rendered in the Container. + */ + children?: React.ReactNode; + /** + * Sets the height of the container to be full viewport height. + * @default false + */ + isFullViewportHeight?: boolean; }; -HeroBanner.defaultProps = { - backgroundImageSource: '', - className: undefined, - children: undefined, - isFullViewportHeight: false, -}; - -function HeroBanner({ backgroundImageSource, children, className, isFullViewportHeight, title }) { +function HeroBanner({ + backgroundImageSource, + children, + className, + isFullViewportHeight = false, + title, +}: HeroBannerPropsType) { return ( ; - -// Default HeroBanner supplied with only required args -export const Default = Template.bind({}); -Default.args = { - title: 'Banner Title', -}; diff --git a/components/HeroBanner/__stories__/HeroBanner.stories.tsx b/components/HeroBanner/__stories__/HeroBanner.stories.tsx new file mode 100644 index 000000000..470dcf8a8 --- /dev/null +++ b/components/HeroBanner/__stories__/HeroBanner.stories.tsx @@ -0,0 +1,18 @@ +import { Meta, StoryObj } from '@storybook/react'; +import HeroBanner from '../HeroBanner'; + +type HeroBannerStoryType = StoryObj; + +const meta: Meta = { + title: 'HeroBanner', + component: HeroBanner, + args: { + title: 'Banner Title', + }, +}; + +export default meta; + +export const Default: HeroBannerStoryType = { + render: args => , +}; diff --git a/components/HeroBanner/__tests__/HeroBanner.test.js b/components/HeroBanner/__tests__/HeroBanner.test.tsx similarity index 100% rename from components/HeroBanner/__tests__/HeroBanner.test.js rename to components/HeroBanner/__tests__/HeroBanner.test.tsx diff --git a/components/HeroBanner/__tests__/__snapshots__/HeroBanner.test.js.snap b/components/HeroBanner/__tests__/__snapshots__/HeroBanner.test.tsx.snap similarity index 100% rename from components/HeroBanner/__tests__/__snapshots__/HeroBanner.test.js.snap rename to components/HeroBanner/__tests__/__snapshots__/HeroBanner.test.tsx.snap diff --git a/components/Modal/Modal.js b/components/Modal/Modal.tsx similarity index 67% rename from components/Modal/Modal.js rename to components/Modal/Modal.tsx index e766e7db7..ae685fccc 100644 --- a/components/Modal/Modal.js +++ b/components/Modal/Modal.tsx @@ -1,42 +1,59 @@ -import { node, string, bool, func } from 'prop-types'; import classNames from 'classnames'; import * as Dialog from '@radix-ui/react-dialog'; import { gtag } from 'common/utils/thirdParty/gtag'; import CloseButton from 'components/Buttons/CloseButton/CloseButton'; import { MODAL_CONTENT, MODAL_OVERLAY } from 'common/constants/testIDs'; -Modal.propTypes = { - children: node.isRequired, - className: string, - isOpen: bool, - onRequestClose: func.isRequired, - screenReaderLabel: string.isRequired, // basically a summarizing title - canClose: bool, - childrenClassName: string, -}; - -Modal.defaultProps = { - className: undefined, - isOpen: false, - canClose: true, - childrenClassName: undefined, +export type ModalPropsType = { + /** + * Content to be rendered in the modal. + */ + children: React.ReactNode; + /** + * Function that is called when the user clicks the close button. + */ + onRequestClose: (arg1: any) => void; + /** + * Applies a label for the screen reader. + */ + screenReaderLabel: string; + /** + * Applies style classes to the wrapping div. + */ + className?: string; + /** + * Sets if the modal is open an visible (or not) + * @default false + */ + isOpen?: boolean; + /** + * Sets if the modal can be closed by the user + * @default true + */ + canClose?: boolean; + /** + * Applies style classes to the child content. + */ + childrenClassName?: string; }; function Modal({ children, className, - isOpen, + isOpen = false, onRequestClose, screenReaderLabel, - canClose, + canClose = true, childrenClassName, -}) { +}: ModalPropsType) { if (isOpen) { gtag.modalView(screenReaderLabel); } const portalContainer = - typeof window !== 'undefined' ? document.querySelector('#__next') ?? undefined : undefined; + typeof window !== 'undefined' + ? (document.querySelector('#__next') as HTMLElement) ?? undefined + : undefined; return ( diff --git a/components/Modal/__stories__/Modal.stories.js b/components/Modal/__stories__/Modal.stories.tsx similarity index 71% rename from components/Modal/__stories__/Modal.stories.js rename to components/Modal/__stories__/Modal.stories.tsx index 5601a268f..8a1374920 100644 --- a/components/Modal/__stories__/Modal.stories.js +++ b/components/Modal/__stories__/Modal.stories.tsx @@ -1,17 +1,36 @@ +import { Meta, StoryObj } from '@storybook/react'; import { useState } from 'react'; import isChromatic from 'chromatic/isChromatic'; - import { descriptions } from 'common/constants/descriptions'; import Button from 'components/Buttons/Button/Button'; import Modal from '../Modal'; -export const Default = { +type ModalStoryType = StoryObj; + +const meta: Meta = { + title: 'Modal', + component: Modal, + parameters: { + previewTabs: { + 'storybook/docs/panel': { hidden: true }, + }, + docs: { + autodocs: false, + disable: true, + page: null, + }, + }, +}; + +export default meta; + +export const Default: ModalStoryType = { render: args => { const [isDemoModalOpen, setIsDemoModalOpen] = useState(args.isOpen); return ( <> - + { - const [isDemoModalOpen, setIsDemoModalOpen] = useState(args.isOpen); - - return ( - <> - - - setIsDemoModalOpen(!prevValue)} - /> - - ); - }, +export const NonDismissableModal: ModalStoryType = { + ...Default, args: { canClose: false, isOpen: false, @@ -59,20 +64,3 @@ export const NonDismissableModal = { screenReaderLabel: 'You have completed the form.', }, }; - -const meta = { - title: 'Modal', - component: Modal, - parameters: { - previewTabs: { - 'storybook/docs/panel': { hidden: true }, - }, - docs: { - autodocs: false, - disable: true, - page: null, - }, - }, -}; - -export default meta; diff --git a/components/Modal/__tests__/Modal.test.js b/components/Modal/__tests__/Modal.test.tsx similarity index 93% rename from components/Modal/__tests__/Modal.test.js rename to components/Modal/__tests__/Modal.test.tsx index 4b4af43d2..6907bd97f 100644 --- a/components/Modal/__tests__/Modal.test.js +++ b/components/Modal/__tests__/Modal.test.tsx @@ -24,7 +24,7 @@ describe('Modal', () => { it('should render with many props assigned', () => { const { container } = render( - + Test , ); diff --git a/components/Modal/__tests__/__snapshots__/Modal.test.js.snap b/components/Modal/__tests__/__snapshots__/Modal.test.tsx.snap similarity index 100% rename from components/Modal/__tests__/__snapshots__/Modal.test.js.snap rename to components/Modal/__tests__/__snapshots__/Modal.test.tsx.snap diff --git a/components/ReusableSections/DonateSection/DonateSection.js b/components/ReusableSections/DonateSection/DonateSection.tsx similarity index 100% rename from components/ReusableSections/DonateSection/DonateSection.js rename to components/ReusableSections/DonateSection/DonateSection.tsx diff --git a/components/ReusableSections/DonateSection/__stories__/DonateSection.stories.js b/components/ReusableSections/DonateSection/__stories__/DonateSection.stories.js deleted file mode 100644 index 8e1e04467..000000000 --- a/components/ReusableSections/DonateSection/__stories__/DonateSection.stories.js +++ /dev/null @@ -1,10 +0,0 @@ -import DonateSection from '../DonateSection'; - -export default { - component: DonateSection, - title: 'Reusable/DonateSection', -}; - -const Template = arguments_ => ; - -export const Default = Template.bind({}); diff --git a/components/ReusableSections/DonateSection/__stories__/DonateSection.stories.tsx b/components/ReusableSections/DonateSection/__stories__/DonateSection.stories.tsx new file mode 100644 index 000000000..6b3c14900 --- /dev/null +++ b/components/ReusableSections/DonateSection/__stories__/DonateSection.stories.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { Meta, StoryObj } from '@storybook/react'; +import DonateSection from '../DonateSection'; + +type DonateSectionStoryType = StoryObj; + +const meta: Meta = { + title: 'Reusable/DonateSection', + component: DonateSection, +}; + +export default meta; + +export const Default: DonateSectionStoryType = { + render: args => , +}; diff --git a/components/ReusableSections/DonateSection/__tests__/DonateSection.test.js b/components/ReusableSections/DonateSection/__tests__/DonateSection.test.tsx similarity index 100% rename from components/ReusableSections/DonateSection/__tests__/DonateSection.test.js rename to components/ReusableSections/DonateSection/__tests__/DonateSection.test.tsx diff --git a/components/ReusableSections/DonateSection/__tests__/__snapshots__/DonateSection.test.js.snap b/components/ReusableSections/DonateSection/__tests__/__snapshots__/DonateSection.test.tsx.snap similarity index 93% rename from components/ReusableSections/DonateSection/__tests__/__snapshots__/DonateSection.test.js.snap rename to components/ReusableSections/DonateSection/__tests__/__snapshots__/DonateSection.test.tsx.snap index 4722fbb74..308afefa9 100644 --- a/components/ReusableSections/DonateSection/__tests__/__snapshots__/DonateSection.test.js.snap +++ b/components/ReusableSections/DonateSection/__tests__/__snapshots__/DonateSection.test.tsx.snap @@ -5,8 +5,6 @@ exports[`DonateSection > should render with no props passed passed 1`] = ` backgroundImageSource="https://operation-code-assets.s3.us-east-2.amazonaws.com/background_flag.jpg" >