From 4bdfb6794f65b49e6141cef29c8095cd1126c307 Mon Sep 17 00:00:00 2001 From: Ahmed Ghoneim Date: Wed, 8 Dec 2021 20:20:20 +0200 Subject: [PATCH] feat(client): migrate layout/default to ts (#43866) * chore: rename Default.js to default.tsx * chore: refactor default layout to typescript * use TFunction for type Co-authored-by: Shaun Hamilton --- .../client-only-routes/show-certification.tsx | 8 +-- client/src/client-only-routes/show-user.tsx | 9 +-- .../layouts/{Default.js => default.tsx} | 72 ++++++++----------- client/src/components/layouts/index.ts | 2 +- client/src/declarations.d.ts | 4 ++ client/src/redux/prop-types.ts | 7 ++ 6 files changed, 48 insertions(+), 54 deletions(-) rename client/src/components/layouts/{Default.js => default.tsx} (79%) diff --git a/client/src/client-only-routes/show-certification.tsx b/client/src/client-only-routes/show-certification.tsx index 9063cdc964..cab76980f8 100644 --- a/client/src/client-only-routes/show-certification.tsx +++ b/client/src/client-only-routes/show-certification.tsx @@ -26,7 +26,7 @@ import { userByNameSelector, fetchProfileForUser } from '../redux'; -import { User } from '../redux/prop-types'; +import { UserFetchState, User } from '../redux/prop-types'; import { certMap } from '../resources/cert-and-project-map'; import certificateMissingMessage from '../utils/certificate-missing-message'; import reallyWeirdErrorMessage from '../utils/really-weird-error-message'; @@ -71,9 +71,7 @@ interface ShowCertificationProps { }) => void; signedInUserName: string; user: User; - userFetchState: { - complete: boolean; - }; + userFetchState: UserFetchState; userFullName: string; username: string; } @@ -96,7 +94,7 @@ const mapStateToProps = (state: unknown, props: ShowCertificationProps) => { cert: Cert, fetchState: ShowCertificationProps['fetchState'], signedInUserName: string, - userFetchState: ShowCertificationProps['userFetchState'], + userFetchState: UserFetchState, isDonating: boolean, user ) => ({ diff --git a/client/src/client-only-routes/show-user.tsx b/client/src/client-only-routes/show-user.tsx index d60045e93e..8231fbdc80 100644 --- a/client/src/client-only-routes/show-user.tsx +++ b/client/src/client-only-routes/show-user.tsx @@ -22,6 +22,7 @@ import { userSelector, reportUser } from '../redux'; +import { UserFetchState } from '../redux/prop-types'; interface ShowUserProps { email: string; @@ -31,11 +32,7 @@ interface ShowUserProps { reportDescription: string; }) => void; t: TFunction; - userFetchState: { - pending: boolean; - complete: boolean; - errored: boolean; - }; + userFetchState: UserFetchState; username: string; } @@ -45,7 +42,7 @@ const mapStateToProps = createSelector( userSelector, ( isSignedIn, - userFetchState: ShowUserProps['userFetchState'], + userFetchState: UserFetchState, { email }: { email: string } ) => ({ isSignedIn, diff --git a/client/src/components/layouts/Default.js b/client/src/components/layouts/default.tsx similarity index 79% rename from client/src/components/layouts/Default.js rename to client/src/components/layouts/default.tsx index 15779a8298..f34b39df55 100644 --- a/client/src/components/layouts/Default.js +++ b/client/src/components/layouts/default.tsx @@ -1,10 +1,9 @@ import fontawesome from '@fortawesome/fontawesome'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; +import React, { Component, ReactNode } from 'react'; import Helmet from 'react-helmet'; -import { withTranslation } from 'react-i18next'; +import { TFunction, withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import { bindActionCreators, Dispatch } from 'redux'; import { createSelector } from 'reselect'; import latoBoldURL from '../../../static/fonts/lato/Lato-Bold.woff'; @@ -23,9 +22,9 @@ import { isServerOnlineSelector, userFetchStateSelector, userSelector, - usernameSelector, executeGA } from '../../redux'; +import { UserFetchState, User } from '../../redux/prop-types'; import Flash from '../Flash'; import { flashMessageSelector, removeFlashMessage } from '../Flash/redux'; @@ -38,35 +37,7 @@ import './fonts.css'; import './global.css'; import './variables.css'; -fontawesome.config = { - autoAddCss: false -}; - -const propTypes = { - children: PropTypes.node.isRequired, - executeGA: PropTypes.func, - fetchState: PropTypes.shape({ pending: PropTypes.bool }), - fetchUser: PropTypes.func.isRequired, - flashMessage: PropTypes.shape({ - id: PropTypes.string, - type: PropTypes.string, - message: PropTypes.string - }), - hasMessage: PropTypes.bool, - isOnline: PropTypes.bool.isRequired, - isServerOnline: PropTypes.bool.isRequired, - isSignedIn: PropTypes.bool, - onlineStatusChange: PropTypes.func.isRequired, - pathname: PropTypes.string.isRequired, - removeFlashMessage: PropTypes.func.isRequired, - serverStatusChange: PropTypes.func.isRequired, - showFooter: PropTypes.bool, - signedInUserName: PropTypes.string, - t: PropTypes.func.isRequired, - theme: PropTypes.string, - useTheme: PropTypes.bool, - user: PropTypes.object -}; +fontawesome.config.autoAddCss = false; const mapStateToProps = createSelector( isSignedInSelector, @@ -75,8 +46,14 @@ const mapStateToProps = createSelector( isServerOnlineSelector, userFetchStateSelector, userSelector, - usernameSelector, - (isSignedIn, flashMessage, isOnline, isServerOnline, fetchState, user) => ({ + ( + isSignedIn, + flashMessage, + isOnline: boolean, + isServerOnline: boolean, + fetchState: UserFetchState, + user: User + ) => ({ isSignedIn, flashMessage, hasMessage: !!flashMessage.message, @@ -88,7 +65,9 @@ const mapStateToProps = createSelector( }) ); -const mapDispatchToProps = dispatch => +type StateProps = ReturnType; + +const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators( { fetchUser, @@ -100,7 +79,19 @@ const mapDispatchToProps = dispatch => dispatch ); -class DefaultLayout extends Component { +type DispatchProps = ReturnType; + +interface DefaultLayoutProps extends StateProps, DispatchProps { + children: ReactNode; + pathname: string; + showFooter?: boolean; + t: TFunction; + useTheme?: boolean; +} + +class DefaultLayout extends Component { + static displayName = 'DefaultLayout'; + componentDidMount() { const { isSignedIn, fetchUser, pathname, executeGA } = this.props; if (!isSignedIn) { @@ -112,7 +103,7 @@ class DefaultLayout extends Component { window.addEventListener('offline', this.updateOnlineStatus); } - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: DefaultLayoutProps) { const { pathname, executeGA } = this.props; const { pathname: prevPathname } = prevProps; if (pathname !== prevPathname) { @@ -230,9 +221,6 @@ class DefaultLayout extends Component { } } -DefaultLayout.displayName = 'DefaultLayout'; -DefaultLayout.propTypes = propTypes; - export default connect( mapStateToProps, mapDispatchToProps diff --git a/client/src/components/layouts/index.ts b/client/src/components/layouts/index.ts index a6f5e51958..73d3ed4107 100644 --- a/client/src/components/layouts/index.ts +++ b/client/src/components/layouts/index.ts @@ -1,3 +1,3 @@ export { default as CertificationLayout } from './certification'; -export { default as DefaultLayout } from './Default'; +export { default as DefaultLayout } from './default'; export { default as LearnLayout } from './learn'; diff --git a/client/src/declarations.d.ts b/client/src/declarations.d.ts index 5839596e74..2fbc29895f 100644 --- a/client/src/declarations.d.ts +++ b/client/src/declarations.d.ts @@ -9,6 +9,10 @@ declare module '*.svg' { const content: string; export default content; } +declare module '*.woff' { + const url: string; + export default url; +} declare module '*.png' { const content: string; diff --git a/client/src/redux/prop-types.ts b/client/src/redux/prop-types.ts index 1bc7bfb999..6a6ce48c78 100644 --- a/client/src/redux/prop-types.ts +++ b/client/src/redux/prop-types.ts @@ -347,3 +347,10 @@ export type ChallengeFile = { }; export type ChallengeFiles = ChallengeFile[] | null; + +export interface UserFetchState { + pending: boolean; + complete: boolean; + errored: boolean; + error: string | null; +}