diff --git a/client/modules/About/About.styles.js b/client/modules/About/About.styles.ts similarity index 100% rename from client/modules/About/About.styles.js rename to client/modules/About/About.styles.ts diff --git a/client/modules/About/pages/About.jsx b/client/modules/About/pages/About.tsx similarity index 81% rename from client/modules/About/pages/About.jsx rename to client/modules/About/pages/About.tsx index 840278cbb7..84935a0141 100644 --- a/client/modules/About/pages/About.jsx +++ b/client/modules/About/pages/About.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { Helmet } from 'react-helmet'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; +import type { TFunction } from 'react-i18next'; import { AboutPageContent, Intro, @@ -27,8 +27,34 @@ import packageData from '../../../../package.json'; import HeartIcon from '../../../images/heart.svg'; import AsteriskIcon from '../../../images/p5-asterisk.svg'; import LogoIcon from '../../../images/p5js-square-logo.svg'; +import { RootState } from '../../../reducers'; -const AboutSection = ({ section, t }) => ( +export interface AboutSectionInfoItem { + url: string; + title: string; + description: string; +} +export interface AboutSectionInfoSection { + header: string; + items: AboutSectionInfoItem[]; +} +export interface ContactSectionLink { + label: string; + href: string; +} + +export interface AboutSectionProps { + section: AboutSectionInfoSection; + t: TFunction<'translation'>; +} + +const AboutSection = ({ + section, + t +}: { + section: AboutSectionInfoSection; + t: TFunction<'translation'>; +}) => (

{t(section.header)}

@@ -47,11 +73,15 @@ const AboutSection = ({ section, t }) => (
); -const About = () => { +export const About = () => { const { t } = useTranslation(); - const p5version = useSelector((state) => { - const index = state.files.find((file) => file.name === 'index.html'); + const p5version = useSelector((state: RootState) => { + const index = state.files.find( + (file: { + name: string /** TODO: update once files types are defined in server */; + }) => file.name === 'index.html' + ); return index?.content.match(/\/p5@([\d.]+)\//)?.[1]; }); @@ -91,7 +121,11 @@ const About = () => { {AboutSectionInfo.map((section) => ( - + ))} @@ -152,19 +186,3 @@ const About = () => { ); }; - -AboutSection.propTypes = { - section: PropTypes.shape({ - header: PropTypes.string.isRequired, - items: PropTypes.arrayOf( - PropTypes.shape({ - url: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - description: PropTypes.string.isRequired - }) - ).isRequired - }).isRequired, - t: PropTypes.func.isRequired -}; - -export default About; diff --git a/client/modules/About/statics/aboutData.js b/client/modules/About/statics/aboutData.ts similarity index 91% rename from client/modules/About/statics/aboutData.js rename to client/modules/About/statics/aboutData.ts index a8623cfa7f..d22e6e75fe 100644 --- a/client/modules/About/statics/aboutData.js +++ b/client/modules/About/statics/aboutData.ts @@ -1,4 +1,9 @@ -export const ContactSectionLinks = [ +import type { + ContactSectionLink, + AboutSectionInfoSection +} from '../pages/About'; + +export const ContactSectionLinks: ContactSectionLink[] = [ { label: 'About.Github', href: 'https://github.com/processing/p5.js-web-editor' @@ -22,7 +27,7 @@ export const ContactSectionLinks = [ } ]; -export const AboutSectionInfo = [ +export const AboutSectionInfo: AboutSectionInfoSection[] = [ { header: 'About.NewP5', items: [ diff --git a/client/modules/Legal/components/PolicyContainer.jsx b/client/modules/Legal/components/PolicyContainer.tsx similarity index 86% rename from client/modules/Legal/components/PolicyContainer.jsx rename to client/modules/Legal/components/PolicyContainer.tsx index fdc311d435..d4b1113856 100644 --- a/client/modules/Legal/components/PolicyContainer.jsx +++ b/client/modules/Legal/components/PolicyContainer.tsx @@ -2,7 +2,6 @@ import React from 'react'; import styled from 'styled-components'; import ReactMarkdown from 'react-markdown'; import remarkSlug from 'remark-slug'; -import PropTypes from 'prop-types'; import { remSize, prop } from '../../../theme'; const PolicyContainerMain = styled.main` @@ -48,16 +47,13 @@ const PolicyContainerMain = styled.main` } `; -function PolicyContainer({ policy }) { +export interface PolicyContainerProps { + policy: string; +} +export function PolicyContainer({ policy }: PolicyContainerProps) { return ( {policy} ); } - -PolicyContainer.propTypes = { - policy: PropTypes.string.isRequired -}; - -export default PolicyContainer; diff --git a/client/modules/Legal/pages/CodeOfConduct.jsx b/client/modules/Legal/pages/CodeOfConduct.tsx similarity index 70% rename from client/modules/Legal/pages/CodeOfConduct.jsx rename to client/modules/Legal/pages/CodeOfConduct.tsx index c961ec74b6..d05e4bb78a 100644 --- a/client/modules/Legal/pages/CodeOfConduct.jsx +++ b/client/modules/Legal/pages/CodeOfConduct.tsx @@ -1,13 +1,11 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import Legal from './Legal'; +import { Legal } from './Legal'; -function CodeOfConduct() { +export function CodeOfConduct() { const { t } = useTranslation(); return ( ); } - -export default CodeOfConduct; diff --git a/client/modules/Legal/pages/Legal.jsx b/client/modules/Legal/pages/Legal.tsx similarity index 87% rename from client/modules/Legal/pages/Legal.jsx rename to client/modules/Legal/pages/Legal.tsx index 4ba5cb5bbc..09db520f66 100644 --- a/client/modules/Legal/pages/Legal.jsx +++ b/client/modules/Legal/pages/Legal.tsx @@ -1,5 +1,4 @@ import axios from 'axios'; -import PropTypes from 'prop-types'; import React, { useEffect, useState } from 'react'; import Helmet from 'react-helmet'; import { useTranslation } from 'react-i18next'; @@ -9,7 +8,7 @@ import { RootPage } from '../../../components/RootPage'; import { remSize } from '../../../theme'; import Loader from '../../App/components/loader'; import Nav from '../../IDE/components/Header/Nav'; -import PolicyContainer from '../components/PolicyContainer'; +import { PolicyContainer } from '../components/PolicyContainer'; const StyledTabList = styled.nav` display: flex; @@ -21,8 +20,18 @@ const StyledTabList = styled.nav` gap: ${remSize(19)}; } `; - -function Legal({ policyFile, title }) { +export interface LegalProps { + /** + * Path of the markdown '.md' file, relative to the /public directory. + */ + policyFile: string; + /** + * Used in the HTML tag. + * TODO: pass this to the Nav to use as the mobile title. + */ + title: string; +} +export function Legal({ policyFile, title }: LegalProps) { const { t } = useTranslation(); const [isLoading, setIsLoading] = useState(true); const [policy, setPolicy] = useState(''); @@ -55,17 +64,3 @@ function Legal({ policyFile, title }) { </RootPage> ); } - -Legal.propTypes = { - /** - * Used in the HTML <title> tag. - * TODO: pass this to the Nav to use as the mobile title. - */ - title: PropTypes.string.isRequired, - /** - * Path of the markdown '.md' file, relative to the /public directory. - */ - policyFile: PropTypes.string.isRequired -}; - -export default Legal; diff --git a/client/modules/Legal/pages/PrivacyPolicy.jsx b/client/modules/Legal/pages/PrivacyPolicy.tsx similarity index 70% rename from client/modules/Legal/pages/PrivacyPolicy.jsx rename to client/modules/Legal/pages/PrivacyPolicy.tsx index ef39ed876c..178736709c 100644 --- a/client/modules/Legal/pages/PrivacyPolicy.jsx +++ b/client/modules/Legal/pages/PrivacyPolicy.tsx @@ -1,13 +1,11 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import Legal from './Legal'; +import { Legal } from './Legal'; -function PrivacyPolicy() { +export function PrivacyPolicy() { const { t } = useTranslation(); return ( <Legal policyFile="privacy-policy.md" title={t('Legal.PrivacyPolicy')} /> ); } - -export default PrivacyPolicy; diff --git a/client/modules/Legal/pages/TermsOfUse.jsx b/client/modules/Legal/pages/TermsOfUse.tsx similarity index 70% rename from client/modules/Legal/pages/TermsOfUse.jsx rename to client/modules/Legal/pages/TermsOfUse.tsx index 6b3b553942..45bbfd93a3 100644 --- a/client/modules/Legal/pages/TermsOfUse.jsx +++ b/client/modules/Legal/pages/TermsOfUse.tsx @@ -1,11 +1,9 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import Legal from './Legal'; +import { Legal } from './Legal'; -function TermsOfUse() { +export function TermsOfUse() { const { t } = useTranslation(); return <Legal policyFile="terms-of-use.md" title={t('Legal.TermsOfUse')} />; } - -export default TermsOfUse; diff --git a/client/routes.jsx b/client/routes.jsx index 8926a95bdd..2195d95da2 100644 --- a/client/routes.jsx +++ b/client/routes.jsx @@ -6,10 +6,10 @@ import { Route as RouterRoute, Switch } from 'react-router-dom'; import App from './modules/App/App'; import IDEView from './modules/IDE/pages/IDEView'; import FullView from './modules/IDE/pages/FullView'; -import About from './modules/About/pages/About'; -import CodeOfConduct from './modules/Legal/pages/CodeOfConduct'; -import PrivacyPolicy from './modules/Legal/pages/PrivacyPolicy'; -import TermsOfUse from './modules/Legal/pages/TermsOfUse'; +import { About } from './modules/About/pages/About'; +import { CodeOfConduct } from './modules/Legal/pages/CodeOfConduct'; +import { PrivacyPolicy } from './modules/Legal/pages/PrivacyPolicy'; +import { TermsOfUse } from './modules/Legal/pages/TermsOfUse'; import LoginView from './modules/User/pages/LoginView'; import SignupView from './modules/User/pages/SignupView'; import ResetPasswordView from './modules/User/pages/ResetPasswordView'; diff --git a/package-lock.json b/package-lock.json index 9edffa05e9..f948e6f8dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -171,6 +171,7 @@ "@types/passport": "^1.0.17", "@types/react": "^16.14.0", "@types/react-dom": "^16.9.25", + "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", "@types/sinon": "^17.0.4", "@types/styled-components": "^5.1.34", @@ -16646,6 +16647,16 @@ "@types/react": "^16.0.0" } }, + "node_modules/@types/react-helmet": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.11.tgz", + "integrity": "sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-redux": { "version": "7.1.18", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", @@ -53346,6 +53357,15 @@ "dev": true, "requires": {} }, + "@types/react-helmet": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.11.tgz", + "integrity": "sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-redux": { "version": "7.1.18", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", diff --git a/package.json b/package.json index 643d468aa3..df7a8dc603 100644 --- a/package.json +++ b/package.json @@ -144,9 +144,9 @@ "@types/nodemailer": "^7.0.1", "@types/nodemailer-mailgun-transport": "^1.4.6", "@types/passport": "^1.0.17", - "@types/passport": "^1.0.17", "@types/react": "^16.14.0", "@types/react-dom": "^16.9.25", + "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", "@types/sinon": "^17.0.4", "@types/styled-components": "^5.1.34",