@plone/volto 17.0.0-alpha.24 → 17.0.0-alpha.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +92 -4
  3. package/CONTRIBUTING.md +5 -1
  4. package/README.md +9 -7
  5. package/cypress/support/commands.js +12 -9
  6. package/cypress.config.js +1 -0
  7. package/locales/ca/LC_MESSAGES/volto.po +41 -15
  8. package/locales/ca.json +1 -1
  9. package/locales/de/LC_MESSAGES/volto.po +41 -15
  10. package/locales/de.json +1 -1
  11. package/locales/en/LC_MESSAGES/volto.po +40 -14
  12. package/locales/en.json +1 -1
  13. package/locales/es/LC_MESSAGES/volto.po +69 -43
  14. package/locales/es.json +1 -1
  15. package/locales/eu/LC_MESSAGES/volto.po +40 -14
  16. package/locales/eu.json +1 -1
  17. package/locales/fi/LC_MESSAGES/volto.po +40 -14
  18. package/locales/fi.json +1 -1
  19. package/locales/fr/LC_MESSAGES/volto.po +41 -15
  20. package/locales/fr.json +1 -1
  21. package/locales/it/LC_MESSAGES/volto.po +40 -14
  22. package/locales/it.json +1 -1
  23. package/locales/ja/LC_MESSAGES/volto.po +40 -14
  24. package/locales/ja.json +1 -1
  25. package/locales/nl/LC_MESSAGES/volto.po +41 -15
  26. package/locales/nl.json +1 -1
  27. package/locales/pt/LC_MESSAGES/volto.po +41 -15
  28. package/locales/pt.json +1 -1
  29. package/locales/pt_BR/LC_MESSAGES/volto.po +40 -14
  30. package/locales/pt_BR.json +1 -1
  31. package/locales/ro/LC_MESSAGES/volto.po +41 -15
  32. package/locales/ro.json +1 -1
  33. package/locales/volto.pot +41 -15
  34. package/locales/zh_CN/LC_MESSAGES/volto.po +41 -15
  35. package/locales/zh_CN.json +1 -1
  36. package/package.json +4 -4
  37. package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +90 -0
  38. package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +6 -0
  39. package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +6 -0
  40. package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +6 -0
  41. package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +10 -0
  42. package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +10 -0
  43. package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +30 -0
  44. package/packages/volto-slate/build/messages/src/elementEditor/messages.json +10 -0
  45. package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +6 -0
  46. package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +6 -0
  47. package/packages/volto-slate/package.json +1 -1
  48. package/packages/volto-slate/src/editor/render.jsx +2 -3
  49. package/src/actions/index.js +4 -0
  50. package/src/actions/navroot/navroot.js +16 -0
  51. package/src/actions/navroot/navroot.test.js +15 -0
  52. package/src/actions/relations/relations.js +17 -0
  53. package/src/actions/site/site.js +16 -0
  54. package/src/actions/site/site.test.js +15 -0
  55. package/src/actions/userSession/userSession.js +17 -1
  56. package/src/components/manage/Blocks/Block/Settings.jsx +2 -0
  57. package/src/components/manage/Blocks/Block/Settings.test.jsx +90 -0
  58. package/src/components/manage/Blocks/Image/schema.js +5 -1
  59. package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -11
  60. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +42 -25
  61. package/src/components/manage/Blocks/ToC/View.jsx +75 -13
  62. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +4 -13
  63. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +44 -0
  64. package/src/components/manage/Contents/Contents.jsx +27 -0
  65. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +65 -38
  66. package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +11 -9
  67. package/src/components/manage/Controlpanels/Relations/Relations.jsx +3 -3
  68. package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +8 -7
  69. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +15 -9
  70. package/src/components/manage/Controlpanels/Rules/AddRule.jsx +1 -1
  71. package/src/components/manage/Controlpanels/Rules/EditRule.jsx +1 -1
  72. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +95 -5
  73. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +127 -99
  74. package/src/components/manage/Diff/DiffField.jsx +25 -1
  75. package/src/components/manage/Form/BlockDataForm.jsx +3 -2
  76. package/src/components/manage/Form/BlockDataForm.test.jsx +34 -2
  77. package/src/components/manage/LinksToItem/LinksToItem.jsx +1 -1
  78. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +5 -2
  79. package/src/components/manage/Messages/Messages.jsx +32 -99
  80. package/src/components/manage/Messages/Messages.test.jsx +0 -1
  81. package/src/components/manage/Sharing/Sharing.jsx +50 -21
  82. package/src/components/manage/UniversalLink/UniversalLink.jsx +4 -6
  83. package/src/components/manage/Widgets/ArrayWidget.jsx +3 -1
  84. package/src/components/manage/Widgets/ArrayWidget.test.jsx +45 -1
  85. package/src/components/manage/Widgets/FormFieldWrapper.jsx +1 -1
  86. package/src/components/manage/Widgets/RegistryImageWidget.jsx +210 -0
  87. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +91 -0
  88. package/src/components/manage/Widgets/SelectWidget.jsx +15 -1
  89. package/src/components/manage/Widgets/SelectWidget.test.jsx +45 -1
  90. package/src/components/theme/Comments/Comment.stories.jsx +84 -0
  91. package/src/components/theme/Comments/Comments.jsx +273 -378
  92. package/src/components/theme/ContentMetadataTags/ContentMetadataTags.jsx +37 -3
  93. package/src/components/theme/Login/Login.jsx +159 -241
  94. package/src/components/theme/Logo/Logo.Multilingual.test.jsx +131 -1
  95. package/src/components/theme/Logo/Logo.jsx +35 -29
  96. package/src/components/theme/Logo/Logo.test.jsx +135 -1
  97. package/src/components/theme/Logout/Logout.jsx +36 -83
  98. package/src/components/theme/Navigation/Navigation.jsx +86 -171
  99. package/src/components/theme/Search/SearchTags.jsx +30 -60
  100. package/src/components/theme/SearchWidget/SearchWidget.jsx +15 -3
  101. package/src/components/theme/SearchWidget/SearchWidget.test.jsx +8 -0
  102. package/src/components/theme/Sitemap/Sitemap.jsx +24 -13
  103. package/src/components/theme/Sitemap/Sitemap.test.jsx +23 -2
  104. package/src/components/theme/View/View.jsx +2 -0
  105. package/src/config/ControlPanels.js +0 -1
  106. package/src/config/Widgets.jsx +2 -0
  107. package/src/config/index.js +15 -3
  108. package/src/constants/ActionTypes.js +4 -0
  109. package/src/express-middleware/images.js +1 -0
  110. package/src/helpers/MessageLabels/MessageLabels.js +26 -4
  111. package/src/helpers/Site/index.js +21 -0
  112. package/src/helpers/index.js +1 -0
  113. package/src/reducers/index.js +4 -0
  114. package/src/reducers/navroot/navroot.js +79 -0
  115. package/src/reducers/navroot/navroot.test.js +110 -0
  116. package/src/reducers/relations/relations.js +74 -46
  117. package/src/reducers/site/site.js +51 -0
  118. package/src/reducers/site/site.test.js +67 -0
  119. package/src/reducers/userSession/userSession.js +15 -1
  120. package/src/server.jsx +9 -0
  121. package/test-setup-config.js +1 -0
  122. package/theme/themes/pastanaga/collections/form.overrides +46 -0
  123. package/theme/themes/pastanaga/elements/input.overrides +10 -0
  124. package/theme/themes/pastanaga/elements/label.overrides +10 -0
  125. package/theme/themes/pastanaga/extras/login.less +3 -0
  126. package/webpack-plugins/webpack-less-plugin.js +19 -0
  127. package/.gitignore~ +0 -71
  128. package/news/4547.breaking~ +0 -1
  129. package/package.json~ +0 -444
  130. package/src/config/index.js~ +0 -223
@@ -2,25 +2,18 @@
2
2
  * Logo component.
3
3
  * @module components/theme/Logo/Logo
4
4
  */
5
-
6
- import { defineMessages, useIntl } from 'react-intl';
5
+ import { useEffect } from 'react';
7
6
  import { Image } from 'semantic-ui-react';
8
- import { useSelector } from 'react-redux';
9
- import config from '@plone/volto/registry';
10
- import { UniversalLink } from '@plone/volto/components';
11
- import { toBackendLang } from '@plone/volto/helpers';
7
+ import { ConditionalLink } from '@plone/volto/components';
12
8
  import LogoImage from '@plone/volto/components/theme/Logo/Logo.svg';
13
-
14
- const messages = defineMessages({
15
- site: {
16
- id: 'Site',
17
- defaultMessage: 'Site',
18
- },
19
- plonesite: {
20
- id: 'Plone Site',
21
- defaultMessage: 'Plone Site',
22
- },
23
- });
9
+ import { useSelector, useDispatch } from 'react-redux';
10
+ import { getNavroot } from '@plone/volto/actions';
11
+ import {
12
+ flattenToAppURL,
13
+ hasApiExpander,
14
+ getBaseUrl,
15
+ toPublicURL,
16
+ } from '@plone/volto/helpers';
24
17
 
25
18
  /**
26
19
  * Logo component class.
@@ -29,23 +22,36 @@ const messages = defineMessages({
29
22
  * @returns {string} Markup of the component.
30
23
  */
31
24
  const Logo = () => {
32
- const { settings } = config;
33
- const lang = useSelector((state) => state.intl.locale);
34
- const intl = useIntl();
25
+ const pathname = useSelector((state) => state.router.location.pathname);
26
+ const site = useSelector((state) => state.site.data);
27
+ const navroot = useSelector((state) => state.navroot.data);
28
+ const dispatch = useDispatch();
29
+
30
+ useEffect(() => {
31
+ if (pathname && !hasApiExpander('navroot', getBaseUrl(pathname))) {
32
+ dispatch(getNavroot(getBaseUrl(pathname)));
33
+ }
34
+ }, [dispatch, pathname]);
35
+
36
+ // remove trailing slash
37
+ const currentURL = toPublicURL(pathname).replace(/\/$/, '');
35
38
 
36
39
  return (
37
- <UniversalLink
38
- href={settings.isMultilingual ? `/${toBackendLang(lang)}` : '/'}
39
- title={intl.formatMessage(messages.site)}
40
+ <ConditionalLink
41
+ href={navroot?.navroot?.['@id']}
42
+ title={navroot?.navroot?.title}
43
+ condition={currentURL !== navroot?.navroot?.['@id']}
40
44
  >
41
45
  <Image
42
- src={LogoImage}
43
- alt={intl.formatMessage(messages.plonesite)}
44
- title={intl.formatMessage(messages.plonesite)}
45
- width="158.2"
46
- height="40.7"
46
+ src={
47
+ site['plone.site_logo']
48
+ ? flattenToAppURL(site['plone.site_logo'])
49
+ : LogoImage
50
+ }
51
+ alt={navroot?.navroot?.title}
52
+ title={navroot?.navroot?.title}
47
53
  />
48
- </UniversalLink>
54
+ </ConditionalLink>
49
55
  );
50
56
  };
51
57
 
@@ -4,17 +4,151 @@ import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
6
 
7
+ import config from '@plone/volto/registry';
8
+
7
9
  import Logo from './Logo';
8
10
 
9
11
  const mockStore = configureStore();
10
12
 
13
+ beforeAll(() => {
14
+ config.settings.publicURL = 'http://localhost:3000';
15
+ });
16
+
11
17
  describe('Logo', () => {
12
- it('renders a logo component', () => {
18
+ it('renders a logo component with default config', () => {
19
+ const store = mockStore({
20
+ intl: {
21
+ locale: 'en',
22
+ messages: {},
23
+ },
24
+ navroot: {
25
+ data: {
26
+ id: 'http://localhost:3000/@navroot',
27
+ navroot: {
28
+ '@id': 'http://localhost:3000',
29
+ title: 'Plone Site',
30
+ },
31
+ },
32
+ },
33
+ router: {
34
+ location: {
35
+ pathname: '/',
36
+ },
37
+ },
38
+ site: {
39
+ data: {},
40
+ },
41
+ });
42
+ const component = renderer.create(
43
+ <Provider store={store}>
44
+ <MemoryRouter>
45
+ <Logo />
46
+ </MemoryRouter>
47
+ </Provider>,
48
+ );
49
+ const json = component.toJSON();
50
+ expect(json).toMatchSnapshot();
51
+ });
52
+ it('renders a logo component with a custom logo', () => {
13
53
  const store = mockStore({
14
54
  intl: {
15
55
  locale: 'en',
16
56
  messages: {},
17
57
  },
58
+ navroot: {
59
+ data: {
60
+ id: 'http://localhost:3000/@navroot',
61
+ navroot: {
62
+ '@id': 'http://localhost:3000',
63
+ title: 'Plone Site',
64
+ },
65
+ },
66
+ },
67
+ router: {
68
+ location: {
69
+ pathname: '/',
70
+ },
71
+ },
72
+ site: {
73
+ data: {
74
+ 'plone.site_logo':
75
+ 'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
76
+ },
77
+ },
78
+ });
79
+ const component = renderer.create(
80
+ <Provider store={store}>
81
+ <MemoryRouter>
82
+ <Logo />
83
+ </MemoryRouter>
84
+ </Provider>,
85
+ );
86
+ const json = component.toJSON();
87
+ expect(json).toMatchSnapshot();
88
+ });
89
+ it('renders a logo component with default config in a non-root url', () => {
90
+ const store = mockStore({
91
+ intl: {
92
+ locale: 'en',
93
+ messages: {},
94
+ },
95
+ navroot: {
96
+ data: {
97
+ id: 'http://localhost:3000/@navroot',
98
+ navroot: {
99
+ '@id': 'http://localhost:3000',
100
+ title: 'Plone Site',
101
+ },
102
+ },
103
+ },
104
+ router: {
105
+ location: {
106
+ pathname: '/some-page',
107
+ },
108
+ },
109
+ site: {
110
+ data: {
111
+ 'plone.site_logo':
112
+ 'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
113
+ },
114
+ },
115
+ });
116
+ const component = renderer.create(
117
+ <Provider store={store}>
118
+ <MemoryRouter>
119
+ <Logo />
120
+ </MemoryRouter>
121
+ </Provider>,
122
+ );
123
+ const json = component.toJSON();
124
+ expect(json).toMatchSnapshot();
125
+ });
126
+ it('renders a logo component with a custom logo in a non-root url', () => {
127
+ const store = mockStore({
128
+ intl: {
129
+ locale: 'en',
130
+ messages: {},
131
+ },
132
+ navroot: {
133
+ data: {
134
+ id: 'http://localhost:3000/@navroot',
135
+ navroot: {
136
+ '@id': 'http://localhost:3000',
137
+ title: 'Plone Site',
138
+ },
139
+ },
140
+ },
141
+ router: {
142
+ location: {
143
+ pathname: '/some-page',
144
+ },
145
+ },
146
+ site: {
147
+ data: {
148
+ 'plone.site_logo':
149
+ 'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
150
+ },
151
+ },
18
152
  });
19
153
  const component = renderer.create(
20
154
  <Provider store={store}>
@@ -1,19 +1,11 @@
1
- /**
2
- * Login container.
3
- * @module components/theme/Logout/Logout
4
- */
5
-
6
- import React, { Component } from 'react';
7
- import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
9
- import { compose } from 'redux';
10
- import { defineMessages, injectIntl } from 'react-intl';
1
+ import { useEffect, useMemo } from 'react';
2
+ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
3
+ import { useHistory } from 'react-router-dom';
4
+ import { defineMessages, useIntl } from 'react-intl';
11
5
  import qs from 'query-string';
12
-
13
- import { Login } from '@plone/volto/components';
6
+ import { Login, Toast } from '@plone/volto/components';
14
7
  import { logout, purgeMessages } from '@plone/volto/actions';
15
8
  import { toast } from 'react-toastify';
16
- import { Toast } from '@plone/volto/components';
17
9
 
18
10
  const messages = defineMessages({
19
11
  loggedOut: {
@@ -26,83 +18,44 @@ const messages = defineMessages({
26
18
  },
27
19
  });
28
20
 
29
- /**
30
- * Logout class.
31
- * @class Logout
32
- * @extends Component
33
- */
34
- class Logout extends Component {
35
- /**
36
- * Property types.
37
- * @property {Object} propTypes Property types.
38
- * @static
39
- */
40
- static propTypes = {
41
- logout: PropTypes.func.isRequired,
42
- purgeMessages: PropTypes.func.isRequired,
43
- query: PropTypes.shape({
44
- return_url: PropTypes.string,
45
- }),
46
- };
47
-
48
- /**
49
- * Default properties.
50
- * @property {Object} defaultProps Default properties.
51
- * @static
52
- */
53
- static defaultProps = {
54
- query: null,
55
- };
56
-
57
- componentDidMount() {
58
- this.props.logout();
59
- this.props.purgeMessages();
60
- }
61
-
62
- /**
63
- * Component will receive props
64
- * @method componentWillReceiveProps
65
- * @param {Object} nextProps Next properties
66
- * @returns {undefined}
67
- */
68
- UNSAFE_componentWillReceiveProps(nextProps) {
69
- if (!nextProps.token) {
70
- this.props.history.replace(this.props.returnUrl || '/');
21
+ const Logout = ({ location }) => {
22
+ const token = useSelector((state) => state.userSession.token, shallowEqual);
23
+ const history = useHistory();
24
+ const dispatch = useDispatch();
25
+ const intl = useIntl();
26
+
27
+ const returnUrl = useMemo(
28
+ () =>
29
+ qs.parse(location.search).return_url ||
30
+ location.pathname
31
+ .replace(/\/login\/?$/, '')
32
+ .replace(/\/logout\/?$/, '') ||
33
+ '/',
34
+ [location],
35
+ );
36
+
37
+ useEffect(() => {
38
+ dispatch(logout());
39
+ dispatch(purgeMessages());
40
+ }, [dispatch]);
41
+
42
+ useEffect(() => {
43
+ if (!token) {
44
+ history.replace(returnUrl || '/');
71
45
  if (!toast.isActive('loggedOut')) {
72
46
  toast.info(
73
47
  <Toast
74
48
  info
75
- title={this.props.intl.formatMessage(messages.loggedOut)}
76
- content={this.props.intl.formatMessage(messages.loggedOutContent)}
49
+ title={intl.formatMessage(messages.loggedOut)}
50
+ content={intl.formatMessage(messages.loggedOutContent)}
77
51
  />,
78
52
  { autoClose: false, toastId: 'loggedOut' },
79
53
  );
80
54
  }
81
55
  }
82
- }
56
+ }, [history, returnUrl, intl, token]);
57
+
58
+ return <Login location={{ query: location.query }} isLogout={true} />;
59
+ };
83
60
 
84
- /**
85
- * Render method.
86
- * @method render
87
- * @returns {string} Markup for the component.
88
- */
89
- render() {
90
- return <Login location={{ query: this.props.location.query }} />;
91
- }
92
- }
93
- export default compose(
94
- injectIntl,
95
- connect(
96
- (state, props) => ({
97
- query: qs.parse(props.location.search),
98
- token: state.userSession.token,
99
- returnUrl:
100
- qs.parse(props.location.search).return_url ||
101
- props.location.pathname
102
- .replace(/\/login\/?$/, '')
103
- .replace(/\/logout\/?$/, '') ||
104
- '/',
105
- }),
106
- { logout, purgeMessages },
107
- ),
108
- )(Logout);
61
+ export default Logout;
@@ -1,14 +1,9 @@
1
- /**
2
- * Navigation components.
3
- * @module components/theme/Navigation/Navigation
4
- */
5
-
6
- import React, { Component } from 'react';
1
+ import { useEffect, useState } from 'react';
7
2
  import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
9
- import { compose } from 'redux';
10
- import { defineMessages, injectIntl } from 'react-intl';
3
+ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
4
+ import { defineMessages, useIntl } from 'react-intl';
11
5
  import { Menu } from 'semantic-ui-react';
6
+
12
7
  import cx from 'classnames';
13
8
  import { BodyClass, getBaseUrl, hasApiExpander } from '@plone/volto/helpers';
14
9
  import config from '@plone/volto/registry';
@@ -27,176 +22,96 @@ const messages = defineMessages({
27
22
  },
28
23
  });
29
24
 
30
- /**
31
- * Navigation container class.
32
- * @class Navigation
33
- * @extends Component
34
- */
35
- class Navigation extends Component {
36
- /**
37
- * Property types.
38
- * @property {Object} propTypes Property types.
39
- * @static
40
- */
41
- static propTypes = {
42
- getNavigation: PropTypes.func.isRequired,
43
- pathname: PropTypes.string.isRequired,
44
- items: PropTypes.arrayOf(
45
- PropTypes.shape({
46
- title: PropTypes.string,
47
- url: PropTypes.string,
48
- }),
49
- ).isRequired,
50
- lang: PropTypes.string.isRequired,
51
- };
52
-
53
- static defaultProps = {
54
- token: null,
55
- };
56
-
57
- /**
58
- * Constructor
59
- * @method constructor
60
- * @param {Object} props Component properties
61
- * @constructs Navigation
62
- */
63
- constructor(props) {
64
- super(props);
65
- this.toggleMobileMenu = this.toggleMobileMenu.bind(this);
66
- this.closeMobileMenu = this.closeMobileMenu.bind(this);
67
- this.state = {
68
- isMobileMenuOpen: false,
69
- };
70
- }
25
+ const Navigation = (props) => {
26
+ const intl = useIntl();
27
+ const dispatch = useDispatch();
28
+ const { pathname, type } = props;
29
+ const [isMobileMenuOpen, setisMobileMenuOpen] = useState(false);
30
+ const token = useSelector((state) => state.userSession.token, shallowEqual);
31
+ const items = useSelector((state) => state.navigation.items, shallowEqual);
32
+ const lang = useSelector((state) => state.intl.locale);
71
33
 
72
- componentDidMount() {
34
+ useEffect(() => {
73
35
  const { settings } = config;
74
- if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
75
- this.props.getNavigation(
76
- getBaseUrl(this.props.pathname),
77
- settings.navDepth,
78
- );
36
+ if (!hasApiExpander('navigation', getBaseUrl(pathname))) {
37
+ dispatch(getNavigation(getBaseUrl(pathname), settings.navDepth));
79
38
  }
80
- }
39
+ }, [pathname, token, dispatch]);
81
40
 
82
- /**
83
- * Component will receive props
84
- * @method componentWillReceiveProps
85
- * @param {Object} nextProps Next properties
86
- * @returns {undefined}
87
- */
88
- UNSAFE_componentWillReceiveProps(nextProps) {
89
- const { settings } = config;
90
- if (
91
- nextProps.pathname !== this.props.pathname ||
92
- nextProps.token !== this.props.token
93
- ) {
94
- if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
95
- this.props.getNavigation(
96
- getBaseUrl(nextProps.pathname),
97
- settings.navDepth,
98
- );
99
- }
100
- }
101
- }
102
-
103
- /**
104
- * Toggle mobile menu's open state
105
- * @method toggleMobileMenu
106
- * @returns {undefined}
107
- */
108
- toggleMobileMenu() {
109
- this.setState({ isMobileMenuOpen: !this.state.isMobileMenuOpen });
110
- }
41
+ const toggleMobileMenu = () => {
42
+ setisMobileMenuOpen(!isMobileMenuOpen);
43
+ };
111
44
 
112
- /**
113
- * Close mobile menu
114
- * @method closeMobileMenu
115
- * @returns {undefined}
116
- */
117
- closeMobileMenu() {
118
- if (!this.state.isMobileMenuOpen) {
45
+ const closeMobileMenu = () => {
46
+ if (!isMobileMenuOpen) {
119
47
  return;
120
48
  }
121
- this.setState({ isMobileMenuOpen: false });
122
- }
49
+ setisMobileMenuOpen(false);
50
+ };
123
51
 
124
- /**
125
- * Render method.
126
- * @method render
127
- * @returns {string} Markup for the component.
128
- */
129
- render() {
130
- return (
131
- <nav className="navigation" id="navigation" aria-label="navigation">
132
- <div className="hamburger-wrapper mobile tablet only">
133
- <button
134
- className={cx('hamburger hamburger--spin', {
135
- 'is-active': this.state.isMobileMenuOpen,
136
- })}
137
- aria-label={
138
- this.state.isMobileMenuOpen
139
- ? this.props.intl.formatMessage(messages.closeMobileMenu, {
140
- type: this.props.type,
141
- })
142
- : this.props.intl.formatMessage(messages.openMobileMenu, {
143
- type: this.props.type,
144
- })
145
- }
146
- title={
147
- this.state.isMobileMenuOpen
148
- ? this.props.intl.formatMessage(messages.closeMobileMenu, {
149
- type: this.props.type,
150
- })
151
- : this.props.intl.formatMessage(messages.openMobileMenu, {
152
- type: this.props.type,
153
- })
154
- }
155
- type="button"
156
- onClick={this.toggleMobileMenu}
157
- >
158
- <span className="hamburger-box">
159
- <span className="hamburger-inner" />
160
- </span>
161
- </button>
162
- </div>
163
- <Menu
164
- stackable
165
- pointing
166
- secondary
167
- className="computer large screen widescreen only"
168
- onClick={this.closeMobileMenu}
52
+ return (
53
+ <nav className="navigation" id="navigation" aria-label="navigation">
54
+ <div className="hamburger-wrapper mobile tablet only">
55
+ <button
56
+ className={cx('hamburger hamburger--spin', {
57
+ 'is-active': isMobileMenuOpen,
58
+ })}
59
+ aria-label={
60
+ isMobileMenuOpen
61
+ ? intl.formatMessage(messages.closeMobileMenu, {
62
+ type: type,
63
+ })
64
+ : intl.formatMessage(messages.openMobileMenu, {
65
+ type: type,
66
+ })
67
+ }
68
+ title={
69
+ isMobileMenuOpen
70
+ ? intl.formatMessage(messages.closeMobileMenu, {
71
+ type: type,
72
+ })
73
+ : intl.formatMessage(messages.openMobileMenu, {
74
+ type: type,
75
+ })
76
+ }
77
+ type="button"
78
+ onClick={toggleMobileMenu}
169
79
  >
170
- <NavItems items={this.props.items} lang={this.props.lang} />
171
- </Menu>
172
- <CSSTransition
173
- in={this.state.isMobileMenuOpen}
174
- timeout={500}
175
- classNames="mobile-menu"
176
- unmountOnExit
177
- >
178
- <div key="mobile-menu-key" className="mobile-menu">
179
- <BodyClass className="has-mobile-menu-open" />
180
- <div className="mobile-menu-nav">
181
- <Menu stackable pointing secondary onClick={this.closeMobileMenu}>
182
- <NavItems items={this.props.items} lang={this.props.lang} />
183
- </Menu>
184
- </div>
80
+ <span className="hamburger-box">
81
+ <span className="hamburger-inner" />
82
+ </span>
83
+ </button>
84
+ </div>
85
+ <Menu
86
+ stackable
87
+ pointing
88
+ secondary
89
+ className="computer large screen widescreen only"
90
+ onClick={closeMobileMenu}
91
+ >
92
+ <NavItems items={items} lang={lang} />
93
+ </Menu>
94
+ <CSSTransition
95
+ in={isMobileMenuOpen}
96
+ timeout={500}
97
+ classNames="mobile-menu"
98
+ unmountOnExit
99
+ >
100
+ <div key="mobile-menu-key" className="mobile-menu">
101
+ <BodyClass className="has-mobile-menu-open" />
102
+ <div className="mobile-menu-nav">
103
+ <Menu stackable pointing secondary onClick={closeMobileMenu}>
104
+ <NavItems items={items} lang={lang} />
105
+ </Menu>
185
106
  </div>
186
- </CSSTransition>
187
- </nav>
188
- );
189
- }
190
- }
107
+ </div>
108
+ </CSSTransition>
109
+ </nav>
110
+ );
111
+ };
112
+
113
+ Navigation.propTypes = {
114
+ pathname: PropTypes.string.isRequired,
115
+ };
191
116
 
192
- export default compose(
193
- injectIntl,
194
- connect(
195
- (state) => ({
196
- token: state.userSession.token,
197
- items: state.navigation.items,
198
- lang: state.intl.locale,
199
- }),
200
- { getNavigation },
201
- ),
202
- )(Navigation);
117
+ export default Navigation;