diff --git a/client/src/components/Flash/redux/index.ts b/client/src/components/Flash/redux/index.ts index ab543564c6d..ad34267989d 100644 --- a/client/src/components/Flash/redux/index.ts +++ b/client/src/components/Flash/redux/index.ts @@ -15,7 +15,7 @@ export const flashMessageSelector = (state: State): FlashState['message'] => // ACTION DEFINITIONS -enum FlashActionTypes { +export enum FlashActionTypes { CreateFlashMessage = 'createFlashMessage', RemoveFlashMessage = 'removeFlashMessage' } @@ -49,7 +49,7 @@ export const removeFlashMessage = }); // REDUCER -type ReducerBase = { type: T }; +export type ReducerBase = { type: T }; type ReducerPayload = T extends FlashActionTypes.CreateFlashMessage ? ReducerBase & { diff --git a/client/src/components/Header/index.tsx b/client/src/components/Header/index.tsx index bce18724981..258941b065e 100644 --- a/client/src/components/Header/index.tsx +++ b/client/src/components/Header/index.tsx @@ -4,18 +4,50 @@ /* eslint-disable @typescript-eslint/unbound-method */ import React from 'react'; import Helmet from 'react-helmet'; +import { withTranslation } from 'react-i18next'; +import { connect } from 'react-redux'; +import { bindActionCreators, Dispatch } from 'redux'; +import { createSelector } from 'reselect'; import { User } from '../../redux/prop-types'; - +import { userSelector } from '../../redux/selectors'; +import { FlashMessageArg } from '../../redux/types'; +import Flash from '../Flash'; +import { + FlashActionTypes, + flashMessageSelector, + ReducerBase, + removeFlashMessage +} from '../Flash/redux'; import UniversalNav from './components/universal-nav'; import './header.css'; +const mapStateToProps = createSelector( + flashMessageSelector, + userSelector, + flashMessage => ({ + flashMessage, + hasMessage: !!flashMessage.message + }) +); +const mapDispatchToProps = (dispatch: Dispatch) => + bindActionCreators( + { + removeFlashMessage + }, + dispatch + ); interface HeaderProps { fetchState: { pending: boolean }; user: User; + flashMessage: { id: string } & FlashMessageArg; + hasMessage: boolean; + removeFlashMessage: () => ReducerBase; } +type StateProps = ReturnType & HeaderProps; + export class Header extends React.Component< - HeaderProps, + StateProps, { displayMenu: boolean; isLanguageMenuDisplayed: boolean } > { menuButtonRef: React.RefObject; @@ -83,7 +115,8 @@ export class Header extends React.Component< render(): JSX.Element { const { displayMenu, isLanguageMenuDisplayed } = this.state; - const { fetchState, user } = this.props; + const { fetchState, user, hasMessage, flashMessage, removeFlashMessage } = + this.props; return ( <> @@ -110,6 +143,12 @@ export class Header extends React.Component< user={user} /> + {hasMessage && flashMessage ? ( + + ) : null} ); } @@ -117,4 +156,7 @@ export class Header extends React.Component< Header.displayName = 'Header'; -export default Header; +export default connect( + mapStateToProps, + mapDispatchToProps +)(withTranslation()(Header)); diff --git a/client/src/components/layouts/default.tsx b/client/src/components/layouts/default.tsx index db1d1712575..24636fb7f37 100644 --- a/client/src/components/layouts/default.tsx +++ b/client/src/components/layouts/default.tsx @@ -28,8 +28,6 @@ import { } from '../../redux/selectors'; import { UserFetchState, User } from '../../redux/prop-types'; import BreadCrumb from '../../templates/Challenges/components/bread-crumb'; -import Flash from '../Flash'; -import { flashMessageSelector, removeFlashMessage } from '../Flash/redux'; import SignoutModal from '../signout-modal'; import Footer from '../Footer'; import Header from '../Header'; @@ -44,22 +42,18 @@ import './rtl-layout.css'; const mapStateToProps = createSelector( isSignedInSelector, - flashMessageSelector, isOnlineSelector, isServerOnlineSelector, userFetchStateSelector, userSelector, ( isSignedIn, - flashMessage, isOnline: boolean, isServerOnline: boolean, fetchState: UserFetchState, user: User ) => ({ isSignedIn, - flashMessage, - hasMessage: !!flashMessage.message, isOnline, isServerOnline, fetchState, @@ -74,7 +68,6 @@ const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators( { fetchUser, - removeFlashMessage, onlineStatusChange, serverStatusChange, executeGA @@ -138,13 +131,10 @@ class DefaultLayout extends Component { render() { const { children, - hasMessage, fetchState, - flashMessage, isOnline, isServerOnline, isSignedIn, - removeFlashMessage, showFooter = true, isChallenge = false, block, @@ -226,12 +216,6 @@ class DefaultLayout extends Component { isServerOnline={isServerOnline} isSignedIn={isSignedIn} /> - {hasMessage && flashMessage ? ( - - ) : null} {isChallenge && (