@plone/volto 19.0.0-alpha.35 → 19.0.0-alpha.37

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 (218) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +1 -1
  3. package/locales/af/LC_MESSAGES/volto.po +29 -13
  4. package/locales/af.json +1 -1
  5. package/locales/ar/LC_MESSAGES/volto.po +29 -13
  6. package/locales/ar.json +1 -1
  7. package/locales/bg/LC_MESSAGES/volto.po +29 -13
  8. package/locales/bg.json +1 -1
  9. package/locales/bn/LC_MESSAGES/volto.po +29 -13
  10. package/locales/bn.json +1 -1
  11. package/locales/ca/LC_MESSAGES/volto.po +32 -16
  12. package/locales/ca.json +1 -1
  13. package/locales/cs/LC_MESSAGES/volto.po +30 -14
  14. package/locales/cs.json +1 -1
  15. package/locales/cy/LC_MESSAGES/volto.po +29 -13
  16. package/locales/cy.json +1 -1
  17. package/locales/da/LC_MESSAGES/volto.po +29 -13
  18. package/locales/da.json +1 -1
  19. package/locales/de/LC_MESSAGES/volto.po +32 -16
  20. package/locales/de.json +1 -1
  21. package/locales/el/LC_MESSAGES/volto.po +29 -13
  22. package/locales/el.json +1 -1
  23. package/locales/en/LC_MESSAGES/volto.po +25 -10
  24. package/locales/en.json +1 -1
  25. package/locales/en_AU/LC_MESSAGES/volto.po +29 -13
  26. package/locales/en_AU.json +1 -1
  27. package/locales/en_GB/LC_MESSAGES/volto.po +29 -13
  28. package/locales/en_GB.json +1 -1
  29. package/locales/eo/LC_MESSAGES/volto.po +29 -13
  30. package/locales/eo.json +1 -1
  31. package/locales/es/LC_MESSAGES/volto.po +67 -52
  32. package/locales/es.json +1 -1
  33. package/locales/et/LC_MESSAGES/volto.po +29 -13
  34. package/locales/et.json +1 -1
  35. package/locales/eu/LC_MESSAGES/volto.po +55 -40
  36. package/locales/eu.json +1 -1
  37. package/locales/fa/LC_MESSAGES/volto.po +29 -13
  38. package/locales/fa.json +1 -1
  39. package/locales/fi/LC_MESSAGES/volto.po +30 -14
  40. package/locales/fi.json +1 -1
  41. package/locales/fr/LC_MESSAGES/volto.po +208 -193
  42. package/locales/fr.json +1 -1
  43. package/locales/fu/LC_MESSAGES/volto.po +29 -13
  44. package/locales/fu.json +1 -1
  45. package/locales/gl/LC_MESSAGES/volto.po +58 -43
  46. package/locales/gl.json +1 -1
  47. package/locales/he/LC_MESSAGES/volto.po +29 -13
  48. package/locales/he.json +1 -1
  49. package/locales/hi/LC_MESSAGES/volto.po +34 -18
  50. package/locales/hi.json +1 -1
  51. package/locales/hr/LC_MESSAGES/volto.po +30 -14
  52. package/locales/hr.json +1 -1
  53. package/locales/hu/LC_MESSAGES/volto.po +29 -13
  54. package/locales/hu.json +1 -1
  55. package/locales/hy/LC_MESSAGES/volto.po +29 -13
  56. package/locales/hy.json +1 -1
  57. package/locales/id/LC_MESSAGES/volto.po +29 -13
  58. package/locales/id.json +1 -1
  59. package/locales/it/LC_MESSAGES/volto.po +34 -18
  60. package/locales/it.json +1 -1
  61. package/locales/ja/LC_MESSAGES/volto.po +29 -13
  62. package/locales/ja.json +1 -1
  63. package/locales/ka/LC_MESSAGES/volto.po +29 -13
  64. package/locales/ka.json +1 -1
  65. package/locales/kn/LC_MESSAGES/volto.po +29 -13
  66. package/locales/kn.json +1 -1
  67. package/locales/ko/LC_MESSAGES/volto.po +29 -13
  68. package/locales/ko.json +1 -1
  69. package/locales/lt/LC_MESSAGES/volto.po +30 -14
  70. package/locales/lt.json +1 -1
  71. package/locales/lv/LC_MESSAGES/volto.po +29 -13
  72. package/locales/lv.json +1 -1
  73. package/locales/mi/LC_MESSAGES/volto.po +29 -13
  74. package/locales/mi.json +1 -1
  75. package/locales/mk/LC_MESSAGES/volto.po +29 -13
  76. package/locales/mk.json +1 -1
  77. package/locales/my/LC_MESSAGES/volto.po +29 -13
  78. package/locales/my.json +1 -1
  79. package/locales/nb_NO/LC_MESSAGES/volto.po +29 -13
  80. package/locales/nb_NO.json +1 -1
  81. package/locales/nl/LC_MESSAGES/volto.po +69 -53
  82. package/locales/nl.json +1 -1
  83. package/locales/nn/LC_MESSAGES/volto.po +29 -13
  84. package/locales/nn.json +1 -1
  85. package/locales/pl/LC_MESSAGES/volto.po +30 -14
  86. package/locales/pl.json +1 -1
  87. package/locales/pt/LC_MESSAGES/volto.po +30 -14
  88. package/locales/pt.json +1 -1
  89. package/locales/pt_BR/LC_MESSAGES/volto.po +54 -39
  90. package/locales/pt_BR.json +1 -1
  91. package/locales/rm/LC_MESSAGES/volto.po +29 -13
  92. package/locales/rm.json +1 -1
  93. package/locales/ro/LC_MESSAGES/volto.po +30 -15
  94. package/locales/ro.json +1 -1
  95. package/locales/ru/LC_MESSAGES/volto.po +30 -14
  96. package/locales/ru.json +1 -1
  97. package/locales/sk/LC_MESSAGES/volto.po +30 -14
  98. package/locales/sk.json +1 -1
  99. package/locales/sl/LC_MESSAGES/volto.po +29 -13
  100. package/locales/sl.json +1 -1
  101. package/locales/sm/LC_MESSAGES/volto.po +29 -13
  102. package/locales/sm.json +1 -1
  103. package/locales/sq/LC_MESSAGES/volto.po +29 -13
  104. package/locales/sq.json +1 -1
  105. package/locales/sr/LC_MESSAGES/volto.po +30 -14
  106. package/locales/sr.json +1 -1
  107. package/locales/sr@cyrl/LC_MESSAGES/volto.po +29 -13
  108. package/locales/sr@cyrl.json +1 -1
  109. package/locales/sr@latn/LC_MESSAGES/volto.po +29 -13
  110. package/locales/sr@latn.json +1 -1
  111. package/locales/sv/LC_MESSAGES/volto.po +31 -15
  112. package/locales/sv.json +1 -1
  113. package/locales/ta/LC_MESSAGES/volto.po +30 -15
  114. package/locales/ta.json +1 -1
  115. package/locales/te/LC_MESSAGES/volto.po +29 -13
  116. package/locales/te.json +1 -1
  117. package/locales/th/LC_MESSAGES/volto.po +29 -13
  118. package/locales/th.json +1 -1
  119. package/locales/to/LC_MESSAGES/volto.po +29 -13
  120. package/locales/to.json +1 -1
  121. package/locales/tr/LC_MESSAGES/volto.po +29 -14
  122. package/locales/tr.json +1 -1
  123. package/locales/uk/LC_MESSAGES/volto.po +30 -14
  124. package/locales/uk.json +1 -1
  125. package/locales/vi/LC_MESSAGES/volto.po +29 -13
  126. package/locales/vi.json +1 -1
  127. package/locales/volto.pot +26 -11
  128. package/locales/zh_CN/LC_MESSAGES/volto.po +29 -14
  129. package/locales/zh_CN.json +1 -1
  130. package/locales/zh_Hant/LC_MESSAGES/volto.po +29 -13
  131. package/locales/zh_Hant.json +1 -1
  132. package/locales/zh_Hant_HK/LC_MESSAGES/volto.po +29 -13
  133. package/locales/zh_Hant_HK.json +1 -1
  134. package/package.json +10 -10
  135. package/src/components/manage/Add/Add.test.jsx +10 -3
  136. package/src/components/manage/Aliases/Aliases.test.jsx +5 -2
  137. package/src/components/manage/BlockChooser/BlockChooser.jsx +7 -10
  138. package/src/components/manage/Blocks/Block/Edit.jsx +19 -10
  139. package/src/components/manage/Blocks/Block/Order/Item.jsx +9 -4
  140. package/src/components/manage/Contents/Contents.test.jsx +7 -4
  141. package/src/components/manage/Contents/DropZoneContent.jsx +1 -0
  142. package/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx +7 -4
  143. package/src/components/manage/Controlpanels/Aliases.test.jsx +7 -4
  144. package/src/components/manage/Controlpanels/BlockType.tsx +2 -3
  145. package/src/components/manage/Controlpanels/ContentType.test.jsx +12 -9
  146. package/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx +12 -9
  147. package/src/components/manage/Controlpanels/ContentTypes.jsx +9 -2
  148. package/src/components/manage/Controlpanels/ContentTypes.test.jsx +7 -4
  149. package/src/components/manage/Controlpanels/Controlpanel.test.jsx +7 -4
  150. package/src/components/manage/Controlpanels/Controlpanels.test.jsx +13 -8
  151. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +7 -4
  152. package/src/components/manage/Controlpanels/ModerateComments.test.jsx +7 -4
  153. package/src/components/manage/Controlpanels/Rules/AddRule.test.jsx +7 -4
  154. package/src/components/manage/Controlpanels/Rules/ConfigureRule.test.jsx +9 -6
  155. package/src/components/manage/Controlpanels/Rules/EditRule.test.jsx +7 -4
  156. package/src/components/manage/Controlpanels/Rules/Rules.test.jsx +7 -4
  157. package/src/components/manage/Controlpanels/UndoControlpanel.test.jsx +7 -4
  158. package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.test.jsx +7 -4
  159. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +58 -5
  160. package/src/components/manage/Controlpanels/Users/UsersControlpanel.ssr.test.jsx +624 -0
  161. package/src/components/manage/Controlpanels/Users/UsersControlpanel.test.jsx +21 -8
  162. package/src/components/manage/Delete/Delete.test.jsx +13 -8
  163. package/src/components/manage/Diff/Diff.test.jsx +7 -4
  164. package/src/components/manage/Edit/Edit.test.jsx +11 -6
  165. package/src/components/manage/Form/Form.jsx +6 -1
  166. package/src/components/manage/Form/ModalForm.jsx +164 -88
  167. package/src/components/manage/History/History.test.jsx +15 -8
  168. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +7 -4
  169. package/src/components/manage/Multilingual/ManageTranslations.test.jsx +15 -12
  170. package/src/components/manage/Preferences/ChangePassword.test.jsx +7 -4
  171. package/src/components/manage/Preferences/PersonalPreferences.test.jsx +9 -6
  172. package/src/components/manage/Rules/Rules.test.jsx +5 -2
  173. package/src/components/manage/Sharing/Sharing.test.jsx +9 -6
  174. package/src/components/manage/Sidebar/ObjectBrowser.jsx +7 -0
  175. package/src/components/manage/Sidebar/ObjectBrowserBody.jsx +7 -3
  176. package/src/components/manage/Sidebar/ObjectBrowserBody.test.jsx +52 -0
  177. package/src/components/manage/Sidebar/Sidebar.jsx +2 -0
  178. package/src/components/manage/Sidebar/Sidebar.test.jsx +4 -1
  179. package/src/components/manage/Toolbar/Toolbar.jsx +89 -7
  180. package/src/components/manage/Toolbar/Toolbar.test.jsx +15 -10
  181. package/src/components/manage/Widgets/FormFieldWrapper.jsx +7 -5
  182. package/src/components/manage/Widgets/ObjectBrowserWidget.jsx +1 -0
  183. package/src/components/manage/Widgets/QuerystringWidget.test.jsx +3 -1
  184. package/src/components/manage/Widgets/TextWidget.jsx +4 -0
  185. package/src/components/manage/Widgets/TokenWidget.jsx +142 -186
  186. package/src/components/theme/App/App.test.jsx +13 -10
  187. package/src/components/theme/ContactForm/ContactForm.test.jsx +13 -8
  188. package/src/components/theme/MultilingualRedirector/MultilingualRedirector.test.jsx +6 -3
  189. package/src/components/theme/Search/Search.jsx +218 -328
  190. package/src/components/theme/Search/Search.test.jsx +14 -14
  191. package/src/components/theme/Sitemap/Sitemap.jsx +22 -30
  192. package/src/components/theme/Sitemap/Sitemap.test.jsx +18 -0
  193. package/src/components/theme/Unauthorized/Unauthorized.jsx +23 -30
  194. package/src/components/theme/Unauthorized/Unauthorized.test.jsx +6 -4
  195. package/src/components/theme/View/View.test.jsx +37 -24
  196. package/src/config/index.js +1 -0
  197. package/src/helpers/Api/Api.js +2 -2
  198. package/src/helpers/I18n/I18n.test.ts +44 -0
  199. package/src/helpers/I18n/I18n.ts +31 -0
  200. package/src/helpers/Robots/Robots.js +1 -1
  201. package/src/helpers/Robots/Robots.test.js +34 -0
  202. package/src/helpers/index.js +1 -0
  203. package/theme/themes/pastanaga/collections/form.overrides +21 -0
  204. package/theme/themes/pastanaga/elements/button.overrides +30 -3
  205. package/types/components/manage/Controlpanels/Relations/RelationsMatrix.d.ts +1 -1
  206. package/types/components/manage/Controlpanels/Users/UsersControlpanel.d.ts +2 -6
  207. package/types/components/manage/Controlpanels/Users/UsersControlpanel.ssr.test.d.ts +1 -0
  208. package/types/components/manage/Controlpanels/index.d.ts +1 -1
  209. package/types/components/manage/Multilingual/ManageTranslations.d.ts +1 -1
  210. package/types/components/manage/Sidebar/ObjectBrowser.d.ts +1 -1
  211. package/types/components/manage/Sidebar/ObjectBrowserBody.test.d.ts +1 -0
  212. package/types/components/manage/Widgets/ImageWidget.d.ts +1 -1
  213. package/types/components/manage/Widgets/InternalUrlWidget.d.ts +1 -1
  214. package/types/components/manage/Widgets/UrlWidget.d.ts +1 -1
  215. package/types/components/manage/Widgets/index.d.ts +2 -2
  216. package/types/components/theme/Search/Search.d.ts +1 -1
  217. package/types/helpers/I18n/I18n.d.ts +20 -0
  218. package/types/helpers/index.d.ts +1 -0
@@ -1,26 +1,20 @@
1
- /**
2
- * Search component.
3
- * @module components/theme/Search/Search
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';
1
+ import { useState, useCallback } from 'react';
2
+ import { useSelector, useDispatch } from 'react-redux';
3
+ import { useLocation, useHistory } from 'react-router-dom';
4
+ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
10
5
  import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
11
6
  import { asyncConnect } from '@plone/volto/helpers/AsyncConnect';
12
- import { FormattedMessage } from 'react-intl';
13
7
  import { createPortal } from 'react-dom';
14
8
  import { Container, Pagination, Button, Header } from 'semantic-ui-react';
15
9
  import qs from 'query-string';
16
10
  import classNames from 'classnames';
17
- import { defineMessages, injectIntl } from 'react-intl';
18
11
  import config from '@plone/volto/registry';
19
12
  import Helmet from '@plone/volto/helpers/Helmet/Helmet';
20
13
  import { searchContent } from '@plone/volto/actions/search/search';
21
14
  import SearchTags from '@plone/volto/components/theme/Search/SearchTags';
22
15
  import Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
23
16
  import Icon from '@plone/volto/components/theme/Icon/Icon';
17
+ import { useClient } from '@plone/volto/hooks/client/useClient';
24
18
 
25
19
  import paginationLeftSVG from '@plone/volto/icons/left-key.svg';
26
20
  import paginationRightSVG from '@plone/volto/icons/right-key.svg';
@@ -32,339 +26,235 @@ const messages = defineMessages({
32
26
  },
33
27
  });
34
28
 
35
- /**
36
- * Search class.
37
- * @class SearchComponent
38
- * @extends Component
39
- */
40
- class Search extends Component {
41
- /**
42
- * Property types.
43
- * @property {Object} propTypes Property types.
44
- * @static
45
- */
46
- static propTypes = {
47
- searchContent: PropTypes.func.isRequired,
48
- searchableText: PropTypes.string,
49
- subject: PropTypes.string,
50
- path: PropTypes.string,
51
- items: PropTypes.arrayOf(
52
- PropTypes.shape({
53
- '@id': PropTypes.string,
54
- '@type': PropTypes.string,
55
- title: PropTypes.string,
56
- description: PropTypes.string,
57
- }),
58
- ),
59
- pathname: PropTypes.string.isRequired,
60
- };
61
-
62
- /**
63
- * Default properties.
64
- * @property {Object} defaultProps Default properties.
65
- * @static
66
- */
67
- static defaultProps = {
68
- items: [],
69
- searchableText: null,
70
- subject: null,
71
- path: null,
72
- };
73
-
74
- constructor(props) {
75
- super(props);
76
- this.defaultPageSize = config.settings.defaultPageSize;
77
- this.state = { currentPage: 1, isClient: false, active: 'relevance' };
78
- }
79
-
80
- /**
81
- * Component did mount
82
- * @method componentDidMount
83
- * @returns {undefined}
84
- */
85
- componentDidMount() {
86
- this.doSearch();
87
- this.setState({ isClient: true });
88
- }
29
+ const Search = (props) => {
30
+ const intl = useIntl();
31
+ const dispatch = useDispatch();
32
+ const location = useLocation();
33
+ const history = useHistory();
34
+ const isClient = useClient();
35
+ const { search } = props;
89
36
 
90
- /**
91
- * Component will receive props
92
- * @method componentWillReceiveProps
93
- * @param {Object} nextProps Next properties
94
- * @returns {undefined}
95
- */
96
- UNSAFE_componentWillReceiveProps = (nextProps) => {
97
- if (this.props.location.search !== nextProps.location.search) {
98
- this.doSearch();
99
- }
100
- };
37
+ const defaultPageSize = config.settings.defaultPageSize;
101
38
 
102
- /**
103
- * Search based on the given searchableText, subject and path.
104
- * @method doSearch
105
- * @param {string} searchableText The searchable text string
106
- * @param {string} subject The subject (tag)
107
- * @param {string} path The path to restrict the search to
108
- * @returns {undefined}
109
- */
39
+ const items = useSelector((state) => state.search.items);
40
+ const searchableText = qs.parse(location.search).SearchableText;
41
+ const pathname = location.pathname;
110
42
 
111
- doSearch = () => {
112
- const options = qs.parse(this.props.history.location.search);
113
- this.setState({ currentPage: 1 });
114
- options['use_site_search_settings'] = 1;
115
- this.props.searchContent('', {
116
- b_size: this.defaultPageSize,
117
- ...options,
118
- });
119
- };
43
+ const [currentPage, setCurrentPage] = useState(1);
120
44
 
121
- handleQueryPaginationChange = (e, { activePage }) => {
122
- window.scrollTo(0, 0);
123
- let options = qs.parse(this.props.history.location.search);
124
- options['use_site_search_settings'] = 1;
45
+ const handleQueryPaginationChange = useCallback(
46
+ (e, { activePage }) => {
47
+ window.scrollTo(0, 0);
48
+ const options = qs.parse(location.search);
49
+ options['use_site_search_settings'] = 1;
125
50
 
126
- this.setState({ currentPage: activePage }, () => {
127
- this.props.searchContent('', {
128
- b_size: this.defaultPageSize,
129
- ...options,
130
- b_start:
131
- (this.state.currentPage - 1) *
132
- (options.b_size || this.defaultPageSize),
133
- });
134
- });
135
- };
51
+ setCurrentPage(activePage);
52
+ dispatch(
53
+ searchContent('', {
54
+ b_size: defaultPageSize,
55
+ ...options,
56
+ b_start: (activePage - 1) * (options.b_size || defaultPageSize),
57
+ }),
58
+ );
59
+ },
60
+ [location.search, defaultPageSize, dispatch],
61
+ );
136
62
 
137
- onSortChange = (event, sort_order) => {
138
- let options = qs.parse(this.props.history.location.search);
139
- options.sort_on = event.target.name;
140
- options.sort_order = sort_order || 'ascending';
141
- if (event.target.name === 'relevance') {
142
- delete options.sort_on;
143
- delete options.sort_order;
144
- }
145
- let searchParams = qs.stringify(options);
146
- this.setState({ currentPage: 1, active: event.target.name }, () => {
147
- // eslint-disable-next-line no-restricted-globals
148
- this.props.history.replace({
63
+ const onSortChange = useCallback(
64
+ (event, sort_order) => {
65
+ const options = qs.parse(location.search);
66
+ options.sort_on = event.target.name;
67
+ options.sort_order = sort_order || 'ascending';
68
+ if (event.target.name === 'relevance') {
69
+ delete options.sort_on;
70
+ delete options.sort_order;
71
+ }
72
+ const searchParams = qs.stringify(options);
73
+ history.replace({
149
74
  search: searchParams,
150
75
  });
151
- });
152
- };
153
-
154
- /**
155
- * Render method.
156
- * @method render
157
- * @returns {string} Markup for the component.
158
- */
159
- render() {
160
- const options = qs.parse(this.props.history.location.search);
161
-
162
- return (
163
- <Container id="page-search">
164
- <Helmet title={this.props.intl.formatMessage(messages.Search)} />
165
- <div className="container">
166
- <article id="content">
167
- <header>
168
- <h1 className="documentFirstHeading">
169
- {this.props.searchableText ? (
170
- <FormattedMessage
171
- id="Search results for {term}"
172
- defaultMessage="Search results for {term}"
173
- values={{
174
- term: <q>{this.props.searchableText}</q>,
175
- }}
176
- />
177
- ) : (
178
- <FormattedMessage
179
- id="Search results"
180
- defaultMessage="Search results"
181
- />
182
- )}
183
- </h1>
76
+ },
77
+ [location.search, history],
78
+ );
184
79
 
185
- <SearchTags />
80
+ const options = qs.parse(location.search);
186
81
 
187
- {this.props.search?.items_total > 0 ? (
188
- <div className="items_total">
189
- {this.props.search.items_total}{' '}
190
- <FormattedMessage
191
- id="results found"
192
- defaultMessage="results"
193
- />
194
- <Header>
195
- <Header.Content className="header-content">
196
- <div className="sort-by">
197
- <FormattedMessage
198
- id="Sort By:"
199
- defaultMessage="Sort by:"
200
- />
201
- </div>
202
- <Button
203
- onClick={(event) => {
204
- this.onSortChange(event);
205
- }}
206
- name="relevance"
207
- size="tiny"
208
- className={classNames('button-sort', {
209
- 'button-active': this.state.active === 'relevance',
210
- })}
211
- >
212
- <FormattedMessage
213
- id="Relevance"
214
- defaultMessage="Relevance"
215
- />
216
- </Button>
217
- <Button
218
- onClick={(event) => {
219
- this.onSortChange(event);
220
- }}
221
- name="sortable_title"
222
- size="tiny"
223
- className={classNames('button-sort', {
224
- 'button-active':
225
- this.state.active === 'sortable_title',
226
- })}
227
- >
228
- <FormattedMessage
229
- id="Alphabetically"
230
- defaultMessage="Alphabetically"
231
- />
232
- </Button>
233
- <Button
234
- onClick={(event) => {
235
- this.onSortChange(event, 'reverse');
236
- }}
237
- name="effective"
238
- size="tiny"
239
- className={classNames('button-sort', {
240
- 'button-active': this.state.active === 'effective',
241
- })}
242
- >
243
- <FormattedMessage
244
- id="Date (newest first)"
245
- defaultMessage="Date (newest first)"
246
- />
247
- </Button>
248
- </Header.Content>
249
- </Header>
250
- </div>
82
+ return (
83
+ <Container id="page-search">
84
+ <Helmet title={intl.formatMessage(messages.Search)} />
85
+ <div className="container">
86
+ <article id="content">
87
+ <header>
88
+ <h1 className="documentFirstHeading">
89
+ {searchableText ? (
90
+ <FormattedMessage
91
+ id="Search results for {term}"
92
+ defaultMessage="Search results for {term}"
93
+ values={{
94
+ term: <q>{searchableText}</q>,
95
+ }}
96
+ />
251
97
  ) : (
252
- <div>
253
- <FormattedMessage
254
- id="No results found"
255
- defaultMessage="No results found"
256
- />
257
- </div>
98
+ <FormattedMessage
99
+ id="Search results"
100
+ defaultMessage="Search results"
101
+ />
258
102
  )}
259
- </header>
260
- <section id="content-core">
261
- {this.props.items.map((item) => (
262
- <article className="tileItem" key={item['@id']}>
263
- <h2 className="tileHeadline">
264
- <UniversalLink
265
- item={item}
266
- className="summary url"
267
- title={item['@type']}
268
- >
269
- {item.title}
270
- </UniversalLink>
271
- </h2>
272
- {item.description && (
273
- <div className="tileBody">
274
- <span className="description">{item.description}</span>
103
+ </h1>
104
+
105
+ <SearchTags />
106
+
107
+ {search?.items_total > 0 ? (
108
+ <div className="items_total">
109
+ {search.items_total}{' '}
110
+ <FormattedMessage id="results found" defaultMessage="results" />
111
+ <Header>
112
+ <Header.Content className="header-content">
113
+ <div className="sort-by">
114
+ <FormattedMessage
115
+ id="Sort By:"
116
+ defaultMessage="Sort by:"
117
+ />
275
118
  </div>
276
- )}
277
- <div className="tileFooter">
278
- <UniversalLink item={item}>
119
+ <Button
120
+ onClick={(event) => {
121
+ onSortChange(event);
122
+ }}
123
+ name="relevance"
124
+ size="tiny"
125
+ className={classNames('button-sort', {
126
+ 'button-active': options.sort_on === 'relevance',
127
+ })}
128
+ >
129
+ <FormattedMessage
130
+ id="Relevance"
131
+ defaultMessage="Relevance"
132
+ />
133
+ </Button>
134
+ <Button
135
+ onClick={(event) => {
136
+ onSortChange(event);
137
+ }}
138
+ name="sortable_title"
139
+ size="tiny"
140
+ className={classNames('button-sort', {
141
+ 'button-active': options.sort_on === 'sortable_title',
142
+ })}
143
+ >
144
+ <FormattedMessage
145
+ id="Alphabetically"
146
+ defaultMessage="Alphabetically"
147
+ />
148
+ </Button>
149
+ <Button
150
+ onClick={(event) => {
151
+ onSortChange(event, 'reverse');
152
+ }}
153
+ name="effective"
154
+ size="tiny"
155
+ className={classNames('button-sort', {
156
+ 'button-active': options.sort_on === 'effective',
157
+ })}
158
+ >
279
159
  <FormattedMessage
280
- id="Read More…"
281
- defaultMessage="Read More…"
160
+ id="Date (newest first)"
161
+ defaultMessage="Date (newest first)"
282
162
  />
283
- </UniversalLink>
163
+ </Button>
164
+ </Header.Content>
165
+ </Header>
166
+ </div>
167
+ ) : (
168
+ <div>
169
+ <FormattedMessage
170
+ id="No results found"
171
+ defaultMessage="No results found"
172
+ />
173
+ </div>
174
+ )}
175
+ </header>
176
+ <section id="content-core">
177
+ {items.map((item) => (
178
+ <article className="tileItem" key={item['@id']}>
179
+ <h2 className="tileHeadline">
180
+ <UniversalLink
181
+ item={item}
182
+ className="summary url"
183
+ title={item['@type']}
184
+ >
185
+ {item.title}
186
+ </UniversalLink>
187
+ </h2>
188
+ {item.description && (
189
+ <div className="tileBody">
190
+ <span className="description">{item.description}</span>
284
191
  </div>
285
- <div className="visualClear" />
286
- </article>
287
- ))}
288
-
289
- {this.props.search?.batching && (
290
- <div className="search-footer">
291
- <Pagination
292
- activePage={this.state.currentPage}
293
- totalPages={Math.ceil(
294
- this.props.search.items_total /
295
- (options.b_size || this.defaultPageSize),
296
- )}
297
- onPageChange={this.handleQueryPaginationChange}
298
- firstItem={null}
299
- lastItem={null}
300
- prevItem={{
301
- content: <Icon name={paginationLeftSVG} size="18px" />,
302
- icon: true,
303
- 'aria-disabled': !this.props.search.batching.prev,
304
- className: !this.props.search.batching.prev
305
- ? 'disabled'
306
- : null,
307
- }}
308
- nextItem={{
309
- content: <Icon name={paginationRightSVG} size="18px" />,
310
- icon: true,
311
- 'aria-disabled': !this.props.search.batching.next,
312
- className: !this.props.search.batching.next
313
- ? 'disabled'
314
- : null,
315
- }}
316
- />
192
+ )}
193
+ <div className="tileFooter">
194
+ <UniversalLink item={item}>
195
+ <FormattedMessage
196
+ id="Read More…"
197
+ defaultMessage="Read More…"
198
+ />
199
+ </UniversalLink>
317
200
  </div>
318
- )}
319
- </section>
320
- </article>
321
- </div>
322
- {this.state.isClient &&
323
- createPortal(
324
- <Toolbar
325
- pathname={this.props.pathname}
326
- hideDefaultViewButtons
327
- inner={<span />}
328
- />,
329
- document.getElementById('toolbar'),
330
- )}
331
- </Container>
332
- );
333
- }
334
- }
201
+ <div className="visualClear" />
202
+ </article>
203
+ ))}
335
204
 
336
- export const __test__ = compose(
337
- injectIntl,
338
- connect(
339
- (state, props) => ({
340
- items: state.search.items,
341
- searchableText: qs.parse(props.history.location.search).SearchableText,
342
- pathname: props.history.location.pathname,
343
- }),
344
- { searchContent },
345
- ),
346
- )(Search);
205
+ {search?.batching && (
206
+ <div className="search-footer">
207
+ <Pagination
208
+ activePage={currentPage}
209
+ totalPages={Math.ceil(
210
+ search.items_total / (options.b_size || defaultPageSize),
211
+ )}
212
+ onPageChange={handleQueryPaginationChange}
213
+ firstItem={null}
214
+ lastItem={null}
215
+ prevItem={{
216
+ content: <Icon name={paginationLeftSVG} size="18px" />,
217
+ icon: true,
218
+ 'aria-disabled': !search.batching.prev,
219
+ className: !search.batching.prev ? 'disabled' : null,
220
+ }}
221
+ nextItem={{
222
+ content: <Icon name={paginationRightSVG} size="18px" />,
223
+ icon: true,
224
+ 'aria-disabled': !search.batching.next,
225
+ className: !search.batching.next ? 'disabled' : null,
226
+ }}
227
+ />
228
+ </div>
229
+ )}
230
+ </section>
231
+ </article>
232
+ </div>
233
+ {isClient &&
234
+ createPortal(
235
+ <Toolbar
236
+ pathname={pathname}
237
+ hideDefaultViewButtons
238
+ inner={<span />}
239
+ />,
240
+ document.getElementById('toolbar'),
241
+ )}
242
+ </Container>
243
+ );
244
+ };
347
245
 
348
- export default compose(
349
- injectIntl,
350
- connect(
351
- (state, props) => ({
352
- items: state.search.items,
353
- searchableText: qs.parse(props.history.location.search).SearchableText,
354
- pathname: props.location.pathname,
355
- }),
356
- { searchContent },
357
- ),
358
- asyncConnect([
359
- {
360
- key: 'search',
361
- promise: ({ location, store: { dispatch } }) =>
362
- dispatch(
363
- searchContent('', {
364
- ...qs.parse(location.search),
365
- use_site_search_settings: 1,
366
- }),
367
- ),
368
- },
369
- ]),
370
- )(Search);
246
+ export const __test__ = Search;
247
+
248
+ export default asyncConnect([
249
+ {
250
+ key: 'search',
251
+ promise: ({ location, store: { dispatch } }) =>
252
+ dispatch(
253
+ searchContent('', {
254
+ b_size: config.settings.defaultPageSize,
255
+ ...qs.parse(location.search),
256
+ use_site_search_settings: 1,
257
+ }),
258
+ ),
259
+ },
260
+ ])(Search);
@@ -3,6 +3,7 @@ import { render } from '@testing-library/react';
3
3
  import configureStore from 'redux-mock-store';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import { MemoryRouter } from 'react-router-dom';
6
+ import { CookiesProvider } from 'react-cookie';
6
7
 
7
8
  import { __test__ as Search } from './Search';
8
9
 
@@ -21,21 +22,21 @@ describe('Search', () => {
21
22
  const store = mockStore({
22
23
  search: {
23
24
  loaded: false,
25
+ items: [],
24
26
  },
25
27
  intl: {
26
28
  locale: 'en',
27
29
  messages: {},
28
30
  },
29
31
  });
30
- const history = {
31
- location: { pathname: '/blog', search: '?SearchableText=blog' },
32
- };
33
32
  const { container } = render(
34
33
  <Provider store={store}>
35
- <MemoryRouter>
36
- <Search history={history} />
37
- <div id="toolbar"></div>
38
- </MemoryRouter>
34
+ <CookiesProvider>
35
+ <MemoryRouter initialEntries={['/search?SearchableText=blog']}>
36
+ <Search />
37
+ <div id="toolbar"></div>
38
+ </MemoryRouter>
39
+ </CookiesProvider>
39
40
  </Provider>,
40
41
  );
41
42
 
@@ -60,15 +61,14 @@ describe('Search', () => {
60
61
  messages: {},
61
62
  },
62
63
  });
63
- const history = {
64
- location: { pathname: '/blog', search: '?SearchableText=blog' },
65
- };
66
64
  const { container } = render(
67
65
  <Provider store={store}>
68
- <MemoryRouter>
69
- <Search history={history} />
70
- <div id="toolbar"></div>
71
- </MemoryRouter>
66
+ <CookiesProvider>
67
+ <MemoryRouter initialEntries={['/search?SearchableText=blog']}>
68
+ <Search />
69
+ <div id="toolbar"></div>
70
+ </MemoryRouter>
71
+ </CookiesProvider>
72
72
  </Provider>,
73
73
  );
74
74