feat(client): ts-migrate header components (#42287)
This commit is contained in:
committed by
Mrugesh Mohapatra
parent
e54e2588bf
commit
ea4eeee49e
@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ShallowRenderer from 'react-test-renderer/shallow';
|
import ShallowRenderer from 'react-test-renderer/shallow';
|
||||||
|
|
||||||
import { UniversalNav } from './components/UniversalNav';
|
import { UniversalNav } from './components/universal-nav';
|
||||||
import { NavLinks } from './components/NavLinks';
|
import { NavLinks } from './components/nav-links';
|
||||||
import AuthOrProfile from './components/AuthOrProfile';
|
import AuthOrProfile from './components/auth-or-profile';
|
||||||
|
|
||||||
import envData from '../../../../config/env.json';
|
import envData from '../../../../config/env.json';
|
||||||
|
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||||
|
/* eslint-disable import/no-unresolved */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Button } from '@freecodecamp/react-bootstrap';
|
import { Button } from '@freecodecamp/react-bootstrap';
|
||||||
@ -16,14 +20,21 @@ const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({
|
|||||||
isSignedIn
|
isSignedIn
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function Login(props) {
|
export interface LoginProps {
|
||||||
|
block?: boolean;
|
||||||
|
children?: unknown;
|
||||||
|
'data-test-label'?: string;
|
||||||
|
isSignedIn?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Login = ({
|
||||||
|
block,
|
||||||
|
children,
|
||||||
|
'data-test-label': dataTestLabel,
|
||||||
|
isSignedIn
|
||||||
|
}: LoginProps): JSX.Element => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const {
|
|
||||||
block,
|
|
||||||
'data-test-label': dataTestLabel,
|
|
||||||
children,
|
|
||||||
isSignedIn
|
|
||||||
} = props;
|
|
||||||
const href = isSignedIn ? `${homeLocation}/learn` : `${apiLocation}/signin`;
|
const href = isSignedIn ? `${homeLocation}/learn` : `${apiLocation}/signin`;
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@ -35,14 +46,8 @@ function Login(props) {
|
|||||||
{children || t('buttons.sign-in')}
|
{children || t('buttons.sign-in')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
Login.displayName = 'Login';
|
|
||||||
Login.propTypes = {
|
|
||||||
block: PropTypes.bool,
|
|
||||||
children: PropTypes.any,
|
|
||||||
'data-test-label': PropTypes.string,
|
|
||||||
isSignedIn: PropTypes.bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Login.displayName = 'Login';
|
||||||
|
|
||||||
export default connect(mapStateToProps)(Login);
|
export default connect(mapStateToProps)(Login);
|
@ -1,38 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import AuthOrProfile from './AuthOrProfile';
|
|
||||||
|
|
||||||
const MenuButton = props => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
aria-expanded={props.displayMenu}
|
|
||||||
className={
|
|
||||||
'toggle-button-nav' +
|
|
||||||
(props.displayMenu ? ' reverse-toggle-color' : '')
|
|
||||||
}
|
|
||||||
onClick={props.onClick}
|
|
||||||
ref={props.innerRef}
|
|
||||||
>
|
|
||||||
{t('buttons.menu')}
|
|
||||||
</button>
|
|
||||||
<span className='navatar'>
|
|
||||||
<AuthOrProfile user={props.user} />
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
MenuButton.displayName = 'MenuButton';
|
|
||||||
MenuButton.propTypes = {
|
|
||||||
className: PropTypes.string,
|
|
||||||
displayMenu: PropTypes.bool.isRequired,
|
|
||||||
innerRef: PropTypes.object,
|
|
||||||
onClick: PropTypes.func.isRequired,
|
|
||||||
user: PropTypes.object
|
|
||||||
};
|
|
||||||
|
|
||||||
export default MenuButton;
|
|
@ -1,16 +1,18 @@
|
|||||||
/* eslint-disable react/sort-prop-types */
|
/* eslint-disable @typescript-eslint/ban-types */
|
||||||
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link, borderColorPicker, AvatarRenderer } from '../../helpers';
|
import { Link, borderColorPicker, AvatarRenderer } from '../../helpers';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import Login from './Login';
|
||||||
|
|
||||||
import Login from '../components/Login';
|
export interface AuthOrProfileProps {
|
||||||
|
user?: Object;
|
||||||
const propTypes = {
|
}
|
||||||
user: PropTypes.object
|
const AuthOrProfile = ({ user }: AuthOrProfileProps): JSX.Element => {
|
||||||
};
|
|
||||||
|
|
||||||
export function AuthOrProfile({ user }) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isUserDonating = user && user.isDonating;
|
const isUserDonating = user && user.isDonating;
|
||||||
const isUserSignedIn = user && user.username;
|
const isUserSignedIn = user && user.username;
|
||||||
@ -39,8 +41,7 @@ export function AuthOrProfile({ user }) {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
AuthOrProfile.propTypes = propTypes;
|
|
||||||
AuthOrProfile.displayName = 'AuthOrProfile';
|
AuthOrProfile.displayName = 'AuthOrProfile';
|
||||||
export default AuthOrProfile;
|
export default AuthOrProfile;
|
44
client/src/components/Header/components/menu-button.tsx
Normal file
44
client/src/components/Header/components/menu-button.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-types */
|
||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React, { RefObject } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import AuthOrProfile from './auth-or-profile';
|
||||||
|
|
||||||
|
export interface MenuButtonProps {
|
||||||
|
className?: string;
|
||||||
|
displayMenu?: boolean;
|
||||||
|
innerRef?: RefObject<HTMLButtonElement>;
|
||||||
|
onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined;
|
||||||
|
user?: Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MenuButton = ({
|
||||||
|
displayMenu,
|
||||||
|
innerRef,
|
||||||
|
onClick,
|
||||||
|
user
|
||||||
|
}: MenuButtonProps): JSX.Element => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
aria-expanded={displayMenu}
|
||||||
|
className={
|
||||||
|
'toggle-button-nav' + (displayMenu ? ' reverse-toggle-color' : '')
|
||||||
|
}
|
||||||
|
onClick={onClick}
|
||||||
|
ref={innerRef}
|
||||||
|
>
|
||||||
|
{t('buttons.menu')}
|
||||||
|
</button>
|
||||||
|
<span className='navatar'>
|
||||||
|
<AuthOrProfile user={user} />
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuButton.displayName = 'MenuButton';
|
||||||
|
|
||||||
|
export default MenuButton;
|
@ -1,6 +1,15 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/ban-types */
|
||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||||
|
// @ts-nocheck
|
||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { withTranslation } from 'react-i18next';
|
import { withTranslation } from 'react-i18next';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import {
|
import {
|
||||||
@ -15,33 +24,33 @@ import { updateUserFlag } from '../../../redux/settings';
|
|||||||
import envData from '../../../../../config/env.json';
|
import envData from '../../../../../config/env.json';
|
||||||
import createLanguageRedirect from '../../createLanguageRedirect';
|
import createLanguageRedirect from '../../createLanguageRedirect';
|
||||||
import createExternalRedirect from '../../createExternalRedirects';
|
import createExternalRedirect from '../../createExternalRedirects';
|
||||||
|
import {
|
||||||
const { clientLocale, radioLocation, apiLocation } = envData;
|
|
||||||
|
|
||||||
const {
|
|
||||||
availableLangs,
|
availableLangs,
|
||||||
i18nextCodes,
|
i18nextCodes,
|
||||||
langDisplayNames
|
langDisplayNames
|
||||||
} = require('../../../../../config/i18n/all-langs');
|
} from '../../../../../config/i18n/all-langs';
|
||||||
|
|
||||||
|
const { clientLocale, radioLocation, apiLocation } = envData;
|
||||||
|
|
||||||
const locales = availableLangs.client;
|
const locales = availableLangs.client;
|
||||||
|
|
||||||
const propTypes = {
|
export interface NavLinksProps {
|
||||||
displayMenu: PropTypes.bool,
|
displayMenu?: boolean;
|
||||||
fetchState: PropTypes.shape({ pending: PropTypes.bool }),
|
fetchState?: { pending: boolean };
|
||||||
i18n: PropTypes.object,
|
i18n: Object;
|
||||||
t: PropTypes.func,
|
t: (x: any) => any;
|
||||||
toggleDisplayMenu: PropTypes.func,
|
toggleDisplayMenu?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
toggleNightMode: PropTypes.func.isRequired,
|
toggleNightMode: (x: any) => any;
|
||||||
user: PropTypes.object
|
user?: Record<string, unknown>;
|
||||||
};
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
toggleNightMode: theme => updateUserFlag({ theme })
|
toggleNightMode: (theme: unknown) => updateUserFlag({ theme })
|
||||||
};
|
};
|
||||||
|
|
||||||
export class NavLinks extends Component {
|
export class NavLinks extends Component<NavLinksProps, {}> {
|
||||||
toggleTheme(currentTheme = 'default', toggleNightMode) {
|
static displayName: string;
|
||||||
|
toggleTheme(currentTheme = 'default', toggleNightMode: any) {
|
||||||
toggleNightMode(currentTheme === 'night' ? 'default' : 'night');
|
toggleNightMode(currentTheme === 'night' ? 'default' : 'night');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +63,7 @@ export class NavLinks extends Component {
|
|||||||
toggleDisplayMenu,
|
toggleDisplayMenu,
|
||||||
toggleNightMode,
|
toggleNightMode,
|
||||||
user: { isDonating = false, username, theme }
|
user: { isDonating = false, username, theme }
|
||||||
} = this.props;
|
}: NavLinksProps = this.props;
|
||||||
|
|
||||||
const { pending } = fetchState;
|
const { pending } = fetchState;
|
||||||
return pending ? (
|
return pending ? (
|
||||||
@ -141,7 +150,7 @@ export class NavLinks extends Component {
|
|||||||
}
|
}
|
||||||
disabled={!username}
|
disabled={!username}
|
||||||
key='theme'
|
key='theme'
|
||||||
onClick={() => this.toggleTheme(theme, toggleNightMode)}
|
onClick={() => this.toggleTheme(String(theme), toggleNightMode)}
|
||||||
>
|
>
|
||||||
{username ? (
|
{username ? (
|
||||||
<>
|
<>
|
||||||
@ -165,7 +174,7 @@ export class NavLinks extends Component {
|
|||||||
<button
|
<button
|
||||||
className='nav-link nav-link-lang nav-link-flex'
|
className='nav-link nav-link-lang nav-link-flex'
|
||||||
key={'lang-' + lang}
|
key={'lang-' + lang}
|
||||||
onClick={() => toggleDisplayMenu()}
|
onClick={toggleDisplayMenu}
|
||||||
>
|
>
|
||||||
<span>{langDisplayNames[lang]}</span>
|
<span>{langDisplayNames[lang]}</span>
|
||||||
<FontAwesomeIcon icon={faCheck} />
|
<FontAwesomeIcon icon={faCheck} />
|
||||||
@ -202,7 +211,6 @@ export class NavLinks extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavLinks.propTypes = propTypes;
|
|
||||||
NavLinks.displayName = 'NavLinks';
|
NavLinks.displayName = 'NavLinks';
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps)(withTranslation()(NavLinks));
|
export default connect(null, mapDispatchToProps)(withTranslation()(NavLinks));
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FreeCodeCampLogo from '../../../assets/icons/FreeCodeCamp-logo';
|
import FreeCodeCampLogo from '../../../assets/icons/FreeCodeCamp-logo';
|
||||||
|
|
||||||
function NavLogo() {
|
const NavLogo = (): JSX.Element => {
|
||||||
return <FreeCodeCampLogo />;
|
return <FreeCodeCampLogo />;
|
||||||
}
|
};
|
||||||
|
|
||||||
NavLogo.displayName = 'NavLogo';
|
NavLogo.displayName = 'NavLogo';
|
||||||
export default NavLogo;
|
export default NavLogo;
|
@ -1,20 +1,31 @@
|
|||||||
import React from 'react';
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
import PropTypes from 'prop-types';
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
// @ts-nocheck
|
||||||
|
import React, { Ref } from 'react';
|
||||||
import { Link, SkeletonSprite } from '../../helpers';
|
import { Link, SkeletonSprite } from '../../helpers';
|
||||||
import NavLogo from './NavLogo';
|
import NavLogo from './nav-logo';
|
||||||
import MenuButton from './MenuButton';
|
import MenuButton from './menu-button';
|
||||||
import NavLinks from './NavLinks';
|
import NavLinks from './nav-links';
|
||||||
import './universalNav.css';
|
|
||||||
import { isLanding } from '../../../utils/path-parsers';
|
import { isLanding } from '../../../utils/path-parsers';
|
||||||
|
|
||||||
import Loadable from '@loadable/component';
|
import Loadable from '@loadable/component';
|
||||||
|
|
||||||
|
import './universal-nav.css';
|
||||||
|
|
||||||
const SearchBar = Loadable(() => import('../../search/searchBar/SearchBar'));
|
const SearchBar = Loadable(() => import('../../search/searchBar/SearchBar'));
|
||||||
const SearchBarOptimized = Loadable(() =>
|
const SearchBarOptimized = Loadable(
|
||||||
import('../../search/searchBar/search-bar-optimized')
|
() => import('../../search/searchBar/search-bar-optimized')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export interface UniversalNavProps {
|
||||||
|
displayMenu?: boolean;
|
||||||
|
fetchState?: { pending: boolean };
|
||||||
|
menuButtonRef?: Ref<HTMLButtonElement> | undefined;
|
||||||
|
searchBarRef?: unknown;
|
||||||
|
toggleDisplayMenu?: React.MouseEventHandler<HTMLButtonElement> | undefined;
|
||||||
|
user?: Record<string, unknown>;
|
||||||
|
}
|
||||||
export const UniversalNav = ({
|
export const UniversalNav = ({
|
||||||
displayMenu,
|
displayMenu,
|
||||||
toggleDisplayMenu,
|
toggleDisplayMenu,
|
||||||
@ -22,7 +33,7 @@ export const UniversalNav = ({
|
|||||||
searchBarRef,
|
searchBarRef,
|
||||||
user,
|
user,
|
||||||
fetchState
|
fetchState
|
||||||
}) => {
|
}: UniversalNavProps): JSX.Element => {
|
||||||
const { pending } = fetchState;
|
const { pending } = fetchState;
|
||||||
|
|
||||||
const search =
|
const search =
|
||||||
@ -77,12 +88,3 @@ export const UniversalNav = ({
|
|||||||
|
|
||||||
UniversalNav.displayName = 'UniversalNav';
|
UniversalNav.displayName = 'UniversalNav';
|
||||||
export default UniversalNav;
|
export default UniversalNav;
|
||||||
|
|
||||||
UniversalNav.propTypes = {
|
|
||||||
displayMenu: PropTypes.bool,
|
|
||||||
fetchState: PropTypes.shape({ pending: PropTypes.bool }),
|
|
||||||
menuButtonRef: PropTypes.object,
|
|
||||||
searchBarRef: PropTypes.object,
|
|
||||||
toggleDisplayMenu: PropTypes.func,
|
|
||||||
user: PropTypes.object
|
|
||||||
};
|
|
@ -1,5 +1,8 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Link } from 'gatsby';
|
import { Link } from 'gatsby';
|
||||||
@ -12,21 +15,20 @@ import Login from './Login';
|
|||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
userFetchStateSelector,
|
userFetchStateSelector,
|
||||||
isSignedInSelector,
|
isSignedInSelector,
|
||||||
(fetchState, isSignedIn) => ({
|
(fetchState: any, isSignedIn: any) => ({
|
||||||
isSignedIn,
|
isSignedIn,
|
||||||
showLoading: fetchState.pending
|
showLoading: fetchState.pending
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const propTypes = {
|
export interface UserStateProps {
|
||||||
disableSettings: PropTypes.bool,
|
disableSettings?: boolean;
|
||||||
email: PropTypes.string,
|
email?: string;
|
||||||
isSignedIn: PropTypes.bool,
|
isSignedIn?: boolean;
|
||||||
name: PropTypes.string,
|
name?: string;
|
||||||
showLoading: PropTypes.bool
|
showLoading?: boolean;
|
||||||
};
|
}
|
||||||
|
const UserState = (props: UserStateProps): JSX.Element => {
|
||||||
function UserState(props) {
|
|
||||||
const { isSignedIn, showLoading, disableSettings } = props;
|
const { isSignedIn, showLoading, disableSettings } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -39,7 +41,6 @@ function UserState(props) {
|
|||||||
className='user-state-spinner'
|
className='user-state-spinner'
|
||||||
color='white'
|
color='white'
|
||||||
fadeIn='none'
|
fadeIn='none'
|
||||||
height='38px'
|
|
||||||
name='line-scale'
|
name='line-scale'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -51,9 +52,8 @@ function UserState(props) {
|
|||||||
) : (
|
) : (
|
||||||
<Login />
|
<Login />
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
UserState.displayName = 'UserState';
|
UserState.displayName = 'UserState';
|
||||||
UserState.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(UserState);
|
export default connect(mapStateToProps)(UserState);
|
@ -1,18 +1,28 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/unbound-method */
|
||||||
|
/* eslint-disable @typescript-eslint/ban-types */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import UniversalNav from './components/UniversalNav';
|
import UniversalNav from './components/universal-nav';
|
||||||
|
|
||||||
import './header.css';
|
import './header.css';
|
||||||
|
|
||||||
const propTypes = {
|
export interface HeaderProps {
|
||||||
fetchState: PropTypes.shape({ pending: PropTypes.bool }),
|
fetchState: { pending: boolean };
|
||||||
user: PropTypes.object
|
user: Record<string, any>;
|
||||||
};
|
}
|
||||||
|
export class Header extends React.Component<
|
||||||
export class Header extends React.Component {
|
HeaderProps,
|
||||||
constructor(props) {
|
{ displayMenu: boolean }
|
||||||
|
> {
|
||||||
|
menuButtonRef: React.RefObject<any>;
|
||||||
|
searchBarRef: React.RefObject<any>;
|
||||||
|
static displayName: string;
|
||||||
|
constructor(props: HeaderProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
displayMenu: false
|
displayMenu: false
|
||||||
@ -23,15 +33,15 @@ export class Header extends React.Component {
|
|||||||
this.toggleDisplayMenu = this.toggleDisplayMenu.bind(this);
|
this.toggleDisplayMenu = this.toggleDisplayMenu.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount(): void {
|
||||||
document.addEventListener('click', this.handleClickOutside);
|
document.addEventListener('click', this.handleClickOutside);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount(): void {
|
||||||
document.removeEventListener('click', this.handleClickOutside);
|
document.removeEventListener('click', this.handleClickOutside);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickOutside(event) {
|
handleClickOutside(event: any): void {
|
||||||
if (
|
if (
|
||||||
this.state.displayMenu &&
|
this.state.displayMenu &&
|
||||||
this.menuButtonRef.current &&
|
this.menuButtonRef.current &&
|
||||||
@ -43,10 +53,12 @@ export class Header extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleDisplayMenu() {
|
toggleDisplayMenu(): void {
|
||||||
this.setState(({ displayMenu }) => ({ displayMenu: !displayMenu }));
|
this.setState(({ displayMenu }: { displayMenu: boolean }) => ({
|
||||||
|
displayMenu: !displayMenu
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
render() {
|
render(): JSX.Element {
|
||||||
const { displayMenu } = this.state;
|
const { displayMenu } = this.state;
|
||||||
const { fetchState, user } = this.props;
|
const { fetchState, user } = this.props;
|
||||||
return (
|
return (
|
||||||
@ -69,7 +81,6 @@ export class Header extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Header.propTypes = propTypes;
|
|
||||||
Header.displayName = 'Header';
|
Header.displayName = 'Header';
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
Reference in New Issue
Block a user