From a93a01fa8f04da50a4e40116923b4cd4cf27cc81 Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Mon, 14 Aug 2023 06:48:19 -0400 Subject: [PATCH] MM-54004 migrate HeaderFooterNotLoggedIn as functional component (#24244) * chore: MM-54004 migrate HeaderFooterNotLoggedIn as functional component * fix about and HA links --- server/public/model/config.go | 2 +- .../header_footer_template.test.tsx.snap | 646 +++++++++++------- .../header_footer_template.test.tsx | 154 +++-- .../header_footer_template.tsx | 227 +++--- .../header_footer_template/index.ts | 18 - .../header_footer_template_route.tsx | 2 +- .../src/tests/react_testing_utils.tsx | 3 +- webapp/channels/src/utils/constants.tsx | 2 +- 8 files changed, 601 insertions(+), 453 deletions(-) delete mode 100644 webapp/channels/src/components/header_footer_template/index.ts diff --git a/server/public/model/config.go b/server/public/model/config.go index b5d17dbe713..3484ad2864f 100644 --- a/server/public/model/config.go +++ b/server/public/model/config.go @@ -133,7 +133,7 @@ const ( SupportSettingsDefaultTermsOfServiceLink = "https://mattermost.com/pl/terms-of-use/" SupportSettingsDefaultPrivacyPolicyLink = "https://mattermost.com/pl/privacy-policy/" - SupportSettingsDefaultAboutLink = "https://mattermost.com/pl/about-mattermomst" + SupportSettingsDefaultAboutLink = "https://mattermost.com/pl/about-mattermost" SupportSettingsDefaultHelpLink = "https://mattermost.com/pl/help/" SupportSettingsDefaultReportAProblemLink = "https://mattermost.com/pl/report-a-bug" SupportSettingsDefaultSupportEmail = "" diff --git a/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap b/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap index 47fe7b8fdb6..4665eb90be3 100644 --- a/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap +++ b/webapp/channels/src/components/header_footer_template/__snapshots__/header_footer_template.test.tsx.snap @@ -2,50 +2,56 @@ exports[`components/HeaderFooterTemplate should match snapshot with about link 1`] = `
-
@@ -54,77 +60,86 @@ exports[`components/HeaderFooterTemplate should match snapshot with about link 1 exports[`components/HeaderFooterTemplate should match snapshot with all links 1`] = `
-
@@ -133,44 +148,49 @@ exports[`components/HeaderFooterTemplate should match snapshot with all links 1` exports[`components/HeaderFooterTemplate should match snapshot with children 1`] = `
-

- test -

-
-
+
@@ -179,50 +199,56 @@ exports[`components/HeaderFooterTemplate should match snapshot with children 1`] exports[`components/HeaderFooterTemplate should match snapshot with help link 1`] = `
-
@@ -231,50 +257,56 @@ exports[`components/HeaderFooterTemplate should match snapshot with help link 1` exports[`components/HeaderFooterTemplate should match snapshot with privacy policy link 1`] = `
-
@@ -283,50 +315,56 @@ exports[`components/HeaderFooterTemplate should match snapshot with privacy poli exports[`components/HeaderFooterTemplate should match snapshot with term of service link 1`] = `
-
@@ -335,42 +373,142 @@ exports[`components/HeaderFooterTemplate should match snapshot with term of serv exports[`components/HeaderFooterTemplate should match snapshot without children 1`] = `
-
`; + +exports[`components/HeaderFooterTemplate should set classes on body and #root on mount and unset on unmount 1`] = ` +
+
+
+ +
+
+`; + +exports[`components/HeaderFooterTemplate should set classes on body and #root on mount and unset on unmount 2`] = ` +
+`; diff --git a/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx b/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx index bf52d7947ef..89d030a257d 100644 --- a/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx +++ b/webapp/channels/src/components/header_footer_template/header_footer_template.test.tsx @@ -2,9 +2,13 @@ // See LICENSE.txt for license information. import React from 'react'; -import {shallow} from 'enzyme'; -import NotLoggedIn from 'components/header_footer_template/header_footer_template'; +import {DeepPartial} from '@mattermost/types/utilities'; + +import {renderWithIntlAndStore} from 'tests/react_testing_utils'; +import {GlobalState} from 'types/store'; + +import HeaderFooterNotLoggedIn from './header_footer_template'; describe('components/HeaderFooterTemplate', () => { const RealDate: DateConstructor = Date; @@ -17,13 +21,54 @@ describe('components/HeaderFooterTemplate', () => { global.Date = mock as any; } + const state = { + entities: { + general: { + config: {}, + }, + users: { + currentUserId: '', + profiles: { + user1: { + id: 'user1', + roles: '', + }, + }, + }, + teams: { + currentTeamId: 'team1', + teams: { + team1: { + id: 'team1', + name: 'team-1', + displayName: 'Team 1', + }, + }, + myMembers: { + team1: {roles: 'team_role'}, + }, + }, + }, + storage: { + initialized: true, + }, + } as unknown as GlobalState; + + const renderComponent = (component: React.ReactNode, state: DeepPartial) => { + const rootDiv = document.createElement('div'); + rootDiv.id = 'root'; + rootDiv.setAttribute('data-testid', 'root-testid'); + + return renderWithIntlAndStore( + component, + state, + 'en', + rootDiv, + ); + }; + beforeEach(() => { mockDate(new Date(2017, 6, 1)); - - const elm = document.createElement('div'); - elm.setAttribute('id', 'root'); - document.body.appendChild(elm); - document.body.classList.remove('sticky'); }); afterEach(() => { @@ -31,83 +76,74 @@ describe('components/HeaderFooterTemplate', () => { }); test('should match snapshot without children', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + const {container} = renderComponent(, state as DeepPartial); + expect(container).toMatchSnapshot(); }); test('should match snapshot with children', () => { - const wrapper = shallow( - + const {container} = renderComponent( +

{'test'}

-
, +
, + state as DeepPartial, ); - expect(wrapper).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); test('should match snapshot with help link', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + state.entities.general.config = {HelpLink: 'http://testhelplink'}; + + const {container} = renderComponent(, state as DeepPartial); + expect(container).toMatchSnapshot(); }); test('should match snapshot with term of service link', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + state.entities.general.config = {TermsOfServiceLink: 'http://testtermsofservicelink'}; + + const {container} = renderComponent(, state as DeepPartial); + expect(container).toMatchSnapshot(); }); test('should match snapshot with privacy policy link', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + state.entities.general.config = {PrivacyPolicyLink: 'http://testprivacypolicylink'}; + + const {container} = renderComponent(, state as DeepPartial); + expect(container).toMatchSnapshot(); }); test('should match snapshot with about link', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + state.entities.general.config = {AboutLink: 'http://testaboutlink'}; + + const {container} = renderComponent(, state as DeepPartial); + expect(container).toMatchSnapshot(); }); test('should match snapshot with all links', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + state.entities.general.config = { + HelpLink: 'http://testhelplink', + TermsOfServiceLink: 'http://testtermsofservicelink', + PrivacyPolicyLink: 'http://testprivacypolicylink', + AboutLink: 'http://testaboutlink', + }; + + const {container} = renderComponent(, state as DeepPartial); + expect(container).toMatchSnapshot(); }); - test('should set classes on body and #root on mount', () => { + test('should set classes on body and #root on mount and unset on unmount', () => { + state.entities.general.config = { + HelpLink: 'http://testhelplink', + TermsOfServiceLink: 'http://testtermsofservicelink', + PrivacyPolicyLink: 'http://testprivacypolicylink', + AboutLink: 'http://testaboutlink', + }; expect(document.body.classList.contains('sticky')).toBe(false); - const rootElement: HTMLElement | null = document.getElementById('root'); - expect(rootElement?.classList?.contains('container-fluid')).toBe(true); - shallow(); + const {container, unmount} = renderComponent(, state as DeepPartial); + expect(container).toMatchSnapshot(); expect(document.body.classList.contains('sticky')).toBe(true); - expect(rootElement?.classList?.contains('container-fluid')).toBe(true); - }); - test('should unset classes on body and #root on unmount', () => { + unmount(); expect(document.body.classList.contains('sticky')).toBe(false); - const rootElement: HTMLElement | null = document.getElementById('root'); - expect(rootElement?.classList?.contains('container-fluid')).toBe(true); - const wrapper = shallow( - , - ); - expect(document.body.classList.contains('sticky')).toBe(true); - expect(rootElement?.classList?.contains('container-fluid')).toBe(true); - wrapper.unmount(); - expect(document.body.classList.contains('sticky')).toBe(false); - expect(rootElement?.classList?.contains('container-fluid')).toBe(false); + expect(container).toMatchSnapshot(); }); }); diff --git a/webapp/channels/src/components/header_footer_template/header_footer_template.tsx b/webapp/channels/src/components/header_footer_template/header_footer_template.tsx index 97b9fed2bc2..733c18f94cb 100644 --- a/webapp/channels/src/components/header_footer_template/header_footer_template.tsx +++ b/webapp/channels/src/components/header_footer_template/header_footer_template.tsx @@ -1,142 +1,133 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import PropTypes from 'prop-types'; -import React from 'react'; +import React, {useEffect} from 'react'; +import {useIntl} from 'react-intl'; +import {useSelector} from 'react-redux'; -import {ClientConfig} from '@mattermost/types/config'; +import {getConfig} from 'mattermost-redux/selectors/entities/general'; import ExternalLink from 'components/external_link'; -import {localizeMessage} from 'utils/utils'; type Props = { - config: Partial | undefined; + children?: React.ReactNode | React.ReactNodeArray; } -export default class NotLoggedIn extends React.PureComponent { - static propTypes = { +const HeaderFooterNotLoggedIn = (props: Props) => { + const intl = useIntl(); + const {formatMessage} = intl; + const config = useSelector(getConfig); - /* - * Content of the page - */ - children: PropTypes.object, - - /* - * Mattermost configuration - */ - config: PropTypes.object, - }; - - componentDidMount() { + useEffect(() => { document.body.classList.add('sticky'); const rootElement: HTMLElement | null = document.getElementById('root'); if (rootElement) { rootElement.classList.add('container-fluid'); } - } - componentWillUnmount() { - document.body.classList.remove('sticky'); - const rootElement: HTMLElement | null = document.getElementById('root'); - if (rootElement) { - rootElement.classList.remove('container-fluid'); - } + + return () => { + document.body.classList.remove('sticky'); + const rootElement: HTMLElement | null = document.getElementById('root'); + if (rootElement) { + rootElement.classList.remove('container-fluid'); + } + }; + }, []); + + if (!config) { + return null; } - render() { - const content = []; + const content = []; - if (!this.props.config) { - return null; - } + if (config.AboutLink) { + content.push( + + {formatMessage({id: 'web.footer.about', defaultMessage: 'About'})} + , + ); + } - if (this.props.config.AboutLink) { - content.push( - + {formatMessage({id: 'web.footer.privacy', defaultMessage: 'Privacy Policy'})} + , + ); + } + + if (config.TermsOfServiceLink) { + content.push( + + {formatMessage({id: 'web.footer.terms', defaultMessage: 'Terms'})} + , + ); + } + + if (config.HelpLink) { + content.push( + + {formatMessage({id: 'web.footer.help', defaultMessage: 'Help'})} + , + ); + } + + return ( +
+
+ {props.children} +
+
+