@zengenti/contensis-react-base 4.0.0-beta.9 → 4.0.1-beta.0

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 (212) hide show
  1. package/README.md +14 -1
  2. package/cjs/{App-vZrUfVgQ.js → App-Bg1MzW4V.js} +593 -110
  3. package/cjs/App-Bg1MzW4V.js.map +1 -0
  4. package/cjs/{ChangePassword.container-ECjEXixF.js → ChangePassword.container-C4Du3Wb1.js} +57 -50
  5. package/cjs/ChangePassword.container-C4Du3Wb1.js.map +1 -0
  6. package/cjs/{SSRContext-DVj_QAC1.js → ContensisDeliveryApi-MfcvdfDR.js} +32 -74
  7. package/cjs/ContensisDeliveryApi-MfcvdfDR.js.map +1 -0
  8. package/cjs/CookieConstants-DfPiWCRZ.js +12 -0
  9. package/cjs/CookieConstants-DfPiWCRZ.js.map +1 -0
  10. package/{esm/CookieHelper.class-FTURFpz3.js → cjs/CookieHelper.class-Det3qfdU.js} +4 -6
  11. package/cjs/CookieHelper.class-Det3qfdU.js.map +1 -0
  12. package/cjs/{RouteLoader-D5Yg7EB5.js → RouteLoader-DJeM8cym.js} +17 -9
  13. package/cjs/RouteLoader-DJeM8cym.js.map +1 -0
  14. package/cjs/SSRContext-tMufQDHY.js +116 -0
  15. package/cjs/SSRContext-tMufQDHY.js.map +1 -0
  16. package/cjs/ToJs-BsWqWjdm.js +23 -0
  17. package/cjs/ToJs-BsWqWjdm.js.map +1 -0
  18. package/cjs/{VersionInfo-B_dKCubg.js → VersionInfo-zFPsvS8q.js} +3 -25
  19. package/cjs/VersionInfo-zFPsvS8q.js.map +1 -0
  20. package/cjs/client.js +63 -65
  21. package/cjs/client.js.map +1 -1
  22. package/cjs/contensis-react-base.js +208 -119
  23. package/cjs/contensis-react-base.js.map +1 -1
  24. package/cjs/i18n.js +75 -0
  25. package/cjs/i18n.js.map +1 -0
  26. package/cjs/{ToJs-C9jwV7YB.js → matchGroups-dqONU-vY.js} +2 -22
  27. package/cjs/matchGroups-dqONU-vY.js.map +1 -0
  28. package/cjs/redux.js +8 -6
  29. package/cjs/redux.js.map +1 -1
  30. package/cjs/routing.js +15 -7
  31. package/cjs/routing.js.map +1 -1
  32. package/cjs/{sagas-BVX4Ps1e.js → sagas-BCy9u6zA.js} +523 -375
  33. package/cjs/sagas-BCy9u6zA.js.map +1 -0
  34. package/cjs/search.js +54 -29
  35. package/cjs/search.js.map +1 -1
  36. package/cjs/{selectors-wCs5fHD4.js → selectors-BrxJ8-F8.js} +27 -6
  37. package/cjs/selectors-BrxJ8-F8.js.map +1 -0
  38. package/cjs/selectors-DAQR0uZa.js +18 -0
  39. package/cjs/selectors-DAQR0uZa.js.map +1 -0
  40. package/cjs/slice-5xJMH24n.js +69 -0
  41. package/cjs/slice-5xJMH24n.js.map +1 -0
  42. package/cjs/{store-D07FOXvM.js → store-B7SJs5Hf.js} +64 -5
  43. package/cjs/store-B7SJs5Hf.js.map +1 -0
  44. package/cjs/urls-DGZlAs0y.js +25 -0
  45. package/cjs/urls-DGZlAs0y.js.map +1 -0
  46. package/cjs/user.js +20 -17
  47. package/cjs/user.js.map +1 -1
  48. package/cjs/util-eOjxDjxF.js +148 -0
  49. package/cjs/util-eOjxDjxF.js.map +1 -0
  50. package/cjs/util.js +80 -22
  51. package/cjs/util.js.map +1 -1
  52. package/cjs/{version-CM-bJ62L.js → version-rFG9Y6_B.js} +2 -2
  53. package/cjs/{version-CM-bJ62L.js.map → version-rFG9Y6_B.js.map} +1 -1
  54. package/cjs/{version-B7XFkBhY.js → version-yjHMrfVz.js} +15 -16
  55. package/cjs/version-yjHMrfVz.js.map +1 -0
  56. package/esm/{App-DLZweVSp.js → App-Bplaqueq.js} +554 -72
  57. package/esm/App-Bplaqueq.js.map +1 -0
  58. package/esm/{ChangePassword.container-BgzIy8dA.js → ChangePassword.container-CUBtn82K.js} +19 -13
  59. package/esm/ChangePassword.container-CUBtn82K.js.map +1 -0
  60. package/esm/{SSRContext-BE8ElZ3X.js → ContensisDeliveryApi-LWYXevZ1.js} +30 -67
  61. package/esm/ContensisDeliveryApi-LWYXevZ1.js.map +1 -0
  62. package/esm/CookieConstants-DEmbwzYr.js +7 -0
  63. package/esm/CookieConstants-DEmbwzYr.js.map +1 -0
  64. package/{cjs/CookieHelper.class-C3Eqoze9.js → esm/CookieHelper.class-C6rTRl_1.js} +2 -14
  65. package/esm/CookieHelper.class-C6rTRl_1.js.map +1 -0
  66. package/esm/{RouteLoader-xeQBXywk.js → RouteLoader-CzrlySZf.js} +14 -6
  67. package/esm/RouteLoader-CzrlySZf.js.map +1 -0
  68. package/esm/SSRContext-Bxtg1KGv.js +106 -0
  69. package/esm/SSRContext-Bxtg1KGv.js.map +1 -0
  70. package/esm/ToJs-BnRRHk6f.js +17 -0
  71. package/esm/ToJs-BnRRHk6f.js.map +1 -0
  72. package/esm/{VersionInfo-Cno7K0OA.js → VersionInfo-By2ZCZOh.js} +4 -24
  73. package/esm/VersionInfo-By2ZCZOh.js.map +1 -0
  74. package/esm/client.js +63 -64
  75. package/esm/client.js.map +1 -1
  76. package/esm/contensis-react-base.js +201 -114
  77. package/esm/contensis-react-base.js.map +1 -1
  78. package/esm/i18n.js +64 -0
  79. package/esm/i18n.js.map +1 -0
  80. package/esm/{ToJs-CNzfvyxJ.js → matchGroups-_w8BwzCC.js} +3 -18
  81. package/esm/matchGroups-_w8BwzCC.js.map +1 -0
  82. package/esm/redux.js +11 -8
  83. package/esm/redux.js.map +1 -1
  84. package/esm/routing.js +14 -7
  85. package/esm/routing.js.map +1 -1
  86. package/esm/{sagas-JI51CS37.js → sagas-Fr9yRduO.js} +511 -362
  87. package/esm/sagas-Fr9yRduO.js.map +1 -0
  88. package/esm/search.js +73 -47
  89. package/esm/search.js.map +1 -1
  90. package/esm/{selectors-DO2ocdOp.js → selectors-8ROQrTd7.js} +25 -7
  91. package/esm/selectors-8ROQrTd7.js.map +1 -0
  92. package/esm/selectors-DcmvOeX2.js +10 -0
  93. package/esm/selectors-DcmvOeX2.js.map +1 -0
  94. package/esm/slice-C6JLQik8.js +63 -0
  95. package/esm/slice-C6JLQik8.js.map +1 -0
  96. package/esm/{store-3u0RzHZ0.js → store-B4IrBYHm.js} +64 -6
  97. package/esm/store-B4IrBYHm.js.map +1 -0
  98. package/esm/urls-tLxo_skx.js +22 -0
  99. package/esm/urls-tLxo_skx.js.map +1 -0
  100. package/esm/user.js +9 -6
  101. package/esm/user.js.map +1 -1
  102. package/esm/util-Bl2u6LpY.js +136 -0
  103. package/esm/util-Bl2u6LpY.js.map +1 -0
  104. package/esm/util.js +58 -14
  105. package/esm/util.js.map +1 -1
  106. package/esm/{version-wnf-TITV.js → version-BQAL8sQO.js} +2 -2
  107. package/esm/{version-wnf-TITV.js.map → version-BQAL8sQO.js.map} +1 -1
  108. package/esm/{version-BlsI7hX2.js → version-CA9Mdm3A.js} +16 -16
  109. package/esm/version-CA9Mdm3A.js.map +1 -0
  110. package/i18n/package.json +5 -0
  111. package/models/app/pages/VersionInfo/components/VersionInfo.d.ts +1 -1
  112. package/models/app/pages/VersionInfo/components/VersionInfo.styled.d.ts +1 -2
  113. package/models/i18n/index.d.ts +5 -0
  114. package/models/i18n/redux/sagas.d.ts +19 -0
  115. package/models/i18n/redux/selectors.d.ts +11 -0
  116. package/models/i18n/redux/slice.d.ts +198 -0
  117. package/models/i18n/routes.d.ts +8 -0
  118. package/models/i18n/useI18n.hook.d.ts +20 -0
  119. package/models/index.d.ts +1 -0
  120. package/models/models/AppState.d.ts +2 -0
  121. package/models/models/ContentTypeMapping.d.ts +6 -1
  122. package/models/models/EntryMapper.d.ts +2 -1
  123. package/models/models/Locales.d.ts +11 -0
  124. package/models/models/MatchedRoute.d.ts +5 -1
  125. package/models/models/RouteComponent.d.ts +0 -1
  126. package/models/models/RouteNode.d.ts +4 -2
  127. package/models/models/SSRContext.d.ts +4 -4
  128. package/models/models/StaticRoute.d.ts +12 -1
  129. package/models/models/WithEvents.d.ts +8 -0
  130. package/models/models/config/AppConfig.d.ts +2 -0
  131. package/models/models/config/I18n.d.ts +38 -0
  132. package/models/models/config/ServerConfig.d.ts +14 -0
  133. package/models/redux/index.d.ts +2 -1
  134. package/models/redux/sagas/index.d.ts +3 -1
  135. package/models/redux/sagas/injector.d.ts +13 -0
  136. package/models/redux/store/injectors/index.d.ts +26 -0
  137. package/models/redux/store/injectors/inject.d.ts +24 -0
  138. package/models/redux/store/injectors/util.d.ts +2 -0
  139. package/models/redux/store/store.d.ts +13 -4
  140. package/models/redux/util.d.ts +1 -1
  141. package/models/routing/components/RouteLoader.d.ts +3 -3
  142. package/models/routing/httpContext.d.ts +0 -1
  143. package/models/routing/index.d.ts +1 -0
  144. package/models/routing/redux/actions.d.ts +1 -1
  145. package/models/routing/redux/invokeSearch.d.ts +22 -0
  146. package/models/routing/redux/selectors.d.ts +47 -4
  147. package/models/routing/util/expressions.d.ts +1 -1
  148. package/models/routing/util/find-contenttype-mapping.d.ts +3 -1
  149. package/models/search/containers/withListing.d.ts +1 -1
  150. package/models/search/containers/withSearch.d.ts +1 -1
  151. package/models/search/models/Queries.d.ts +3 -5
  152. package/models/search/models/Search.d.ts +43 -13
  153. package/models/search/models/SearchActions.d.ts +61 -18
  154. package/models/search/models/SearchProps.d.ts +11 -10
  155. package/models/search/models/SearchState.d.ts +23 -2
  156. package/models/search/models/SearchUtil.d.ts +3 -3
  157. package/models/search/redux/getIn.d.ts +2 -2
  158. package/models/search/redux/reducers.d.ts +3 -4
  159. package/models/search/redux/sagas.d.ts +13 -14
  160. package/models/search/redux/schema.d.ts +3 -3
  161. package/models/search/redux/selectors.d.ts +64 -42
  162. package/models/search/redux/util.d.ts +10 -1
  163. package/models/search/search/ContensisDeliveryApi.d.ts +6 -26
  164. package/models/search/search/expressions.d.ts +6 -4
  165. package/models/search/search/util.d.ts +9 -7
  166. package/models/search/transformations/state-to-queryparams.mapper.d.ts +1 -1
  167. package/models/server/features/linkdepth-api/search.d.ts +1 -1
  168. package/models/server/features/response-handler/render-stream.d.ts +2 -4
  169. package/models/server/features/static-assets/index.d.ts +4 -3
  170. package/models/server/internalServer.d.ts +1 -2
  171. package/models/server/middleware/subsiteDebug.d.ts +11 -0
  172. package/models/server/root.d.ts +3 -0
  173. package/models/server/util/bundles.d.ts +9 -9
  174. package/models/server/util/jsx.d.ts +2 -14
  175. package/models/user/components.styled/Login.styled.d.ts +1 -1
  176. package/models/user/components.styled/LoginForm.styled.d.ts +1 -1
  177. package/models/user/hocs/withRegistration.d.ts +1 -1
  178. package/models/util/CachedDeliveryApi.d.ts +8 -2
  179. package/models/util/ContensisDeliveryApi.d.ts +2 -4
  180. package/models/util/NoSSR.d.ts +6 -0
  181. package/models/util/SSRContext.d.ts +3 -19
  182. package/models/util/donotuse_useHistory.d.ts +6 -0
  183. package/models/util/errors.d.ts +16 -0
  184. package/models/util/index.d.ts +7 -2
  185. package/models/util/subsite.d.ts +12 -0
  186. package/models/util/urls.d.ts +1 -2
  187. package/models/util/useIsClient.d.ts +6 -0
  188. package/package.json +37 -39
  189. package/cjs/App-vZrUfVgQ.js.map +0 -1
  190. package/cjs/ChangePassword.container-ECjEXixF.js.map +0 -1
  191. package/cjs/CookieHelper.class-C3Eqoze9.js.map +0 -1
  192. package/cjs/RouteLoader-D5Yg7EB5.js.map +0 -1
  193. package/cjs/SSRContext-DVj_QAC1.js.map +0 -1
  194. package/cjs/ToJs-C9jwV7YB.js.map +0 -1
  195. package/cjs/VersionInfo-B_dKCubg.js.map +0 -1
  196. package/cjs/sagas-BVX4Ps1e.js.map +0 -1
  197. package/cjs/selectors-wCs5fHD4.js.map +0 -1
  198. package/cjs/store-D07FOXvM.js.map +0 -1
  199. package/cjs/version-B7XFkBhY.js.map +0 -1
  200. package/esm/App-DLZweVSp.js.map +0 -1
  201. package/esm/ChangePassword.container-BgzIy8dA.js.map +0 -1
  202. package/esm/CookieHelper.class-FTURFpz3.js.map +0 -1
  203. package/esm/RouteLoader-xeQBXywk.js.map +0 -1
  204. package/esm/SSRContext-BE8ElZ3X.js.map +0 -1
  205. package/esm/ToJs-CNzfvyxJ.js.map +0 -1
  206. package/esm/VersionInfo-Cno7K0OA.js.map +0 -1
  207. package/esm/sagas-JI51CS37.js.map +0 -1
  208. package/esm/selectors-DO2ocdOp.js.map +0 -1
  209. package/esm/store-3u0RzHZ0.js.map +0 -1
  210. package/esm/version-BlsI7hX2.js.map +0 -1
  211. package/models/redux/store/injectors.d.ts +0 -31
  212. package/models/search/search/ToJs.d.ts +0 -4
@@ -5,11 +5,17 @@ var reactRedux = require('react-redux');
5
5
  var reselect = require('reselect');
6
6
  var log = require('loglevel');
7
7
  var effects = require('@redux-saga/core/effects');
8
+ var version = require('./version-rFG9Y6_B.js');
9
+ var ContensisDeliveryApi = require('./ContensisDeliveryApi-MfcvdfDR.js');
8
10
  var contensisDeliveryApi = require('contensis-delivery-api');
9
- var queryString = require('query-string');
11
+ var util = require('./util-eOjxDjxF.js');
12
+ var selectors$1 = require('./selectors-DAQR0uZa.js');
13
+ require('./slice-5xJMH24n.js');
10
14
  var mapJson = require('jsonpath-mapper');
11
15
  var contensisCoreApi = require('contensis-core-api');
12
16
  var merge = require('deepmerge');
17
+ var queryString = require('query-string');
18
+ var selectors$2 = require('./selectors-BrxJ8-F8.js');
13
19
  var _commonjsHelpers = require('./_commonjsHelpers-BJu3ubxk.js');
14
20
 
15
21
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -135,10 +141,12 @@ const navigate = (path, state) => {
135
141
  state
136
142
  };
137
143
  };
138
- const clearFilters$1 = filterKey => {
144
+ const clearFilters$1 = filterKeyOrOptions => {
139
145
  return {
140
146
  type: CLEAR_FILTERS,
141
- filterKey
147
+ clear: typeof filterKeyOrOptions === 'string' ? {
148
+ keys: [filterKeyOrOptions]
149
+ } : filterKeyOrOptions
142
150
  };
143
151
  };
144
152
  const updatePageIndex$1 = (pageIndex, scrollToElement) => {
@@ -239,12 +247,67 @@ const getImmutableOrJS = (state, stateKey, fallbackValue, returnType = globalThi
239
247
  };
240
248
 
241
249
  const getSearchContext = state => getImmutableOrJS(state, ['search', 'context'], Context.facets);
242
- const getCurrent$2 = (state, context = Context.facets) => context === Context.facets ? getCurrentFacet(state) : getCurrentListing(state);
250
+ const getCurrent$2 = (state, context = getSearchContext(state)) => context === Context.facets ? getCurrentFacet(state) : getCurrentListing(state);
243
251
  const getCurrentFacet = state => getImmutableOrJS(state, ['search', 'currentFacet']);
244
252
  const getCurrentListing = state => getImmutableOrJS(state, ['search', 'currentListing']);
245
253
  const getCurrentTab$1 = state => getImmutableOrJS(state, ['search', Context.facets, getCurrentFacet(state), 'tabId'], 0);
254
+ const getCurrentComposition = state => getImmutableOrJS(state, ['search', 'currentComposition']);
255
+
256
+ /** A localised version of `getCurrent` selector */
257
+ const getLocalisedCurrent$2 = (state, language = selectors$1.selectCurrentLanguage(state), context = getSearchContext(state)) => {
258
+ var _facet$i18n;
259
+ const currentFacet = getCurrent$2(state, context);
260
+ const facet = getFacet$1(state, currentFacet, context, 'js');
261
+ const i18n = (_facet$i18n = facet.i18n) === null || _facet$i18n === void 0 ? void 0 : _facet$i18n[language];
262
+ return i18n || currentFacet;
263
+ };
264
+ const getLocalisedFacetKey = (state, facet = getCurrent$2(state), language = selectors$1.selectCurrentLanguage(state), context = getSearchContext(state)) => {
265
+ var _getFacet;
266
+ return (_getFacet = getFacet$1(state, facet, context, 'js')) === null || _getFacet === void 0 || (_getFacet = _getFacet.i18n) === null || _getFacet === void 0 ? void 0 : _getFacet[language];
267
+ };
268
+ const getCurrentFromLocalised = (state, alias, language, context = getSearchContext(state)) => {
269
+ var _state$search;
270
+ const facets = ((_state$search = state.search) === null || _state$search === void 0 ? void 0 : _state$search[context]) || {};
271
+ for (const [facetKey, facet] of Object.entries(facets)) {
272
+ if (language) {
273
+ var _facet$i18n2;
274
+ const languageAlias = (_facet$i18n2 = facet.i18n) === null || _facet$i18n2 === void 0 ? void 0 : _facet$i18n2[language];
275
+ if (languageAlias === alias) {
276
+ return {
277
+ facet: facetKey,
278
+ language
279
+ };
280
+ }
281
+ } else {
282
+ // Fallback to check for any language
283
+ for (const lang in facet.i18n) {
284
+ if (facet.i18n[lang] === alias) {
285
+ return {
286
+ facet: facetKey,
287
+ language: lang
288
+ };
289
+ }
290
+ }
291
+ }
292
+ }
293
+ return null;
294
+ // // Default to returning the inputs
295
+ // return { facet: alias, language };
296
+ };
246
297
  const getFacets = (state, returnType) => getImmutableOrJS(state, ['search', Context.facets], {}, returnType);
247
298
  const getTabFacets$1 = state => Object.fromEntries(Object.entries(getFacets(state, 'js')).filter(([key]) => getImmutableOrJS(getFacets(state), [key, 'tabId'], 0) === getCurrentTab$1(state)));
299
+ const getCompositionFacets = (state, composition) => {
300
+ const currentComposition = composition || getCurrentComposition(state);
301
+ if (!currentComposition) return {};
302
+ const compositionConfig = getSearchCompositions(state)[currentComposition];
303
+ const context = getSearchContext(state);
304
+ if (!compositionConfig[context]) return {};
305
+ const facets = {};
306
+ for (const facet of compositionConfig[context]) {
307
+ facets[facet] = getFacet$1(state, facet, context);
308
+ }
309
+ return facets;
310
+ };
248
311
  const getFacetTitles$1 = state => Object.entries(getFacets(state, 'js')).map(([key, facet = {}]) => {
249
312
  var _facet$pagingInfo;
250
313
  return {
@@ -262,9 +325,42 @@ const getListing$1 = (state, listing = '') => {
262
325
  const currentListing = listing || getCurrentListing(state);
263
326
  return getImmutableOrJS(state, ['search', Context.listings, currentListing], {});
264
327
  };
328
+ const getComposition = (state, composition = '') => {
329
+ const currentComposition = composition || getCurrentComposition(state);
330
+ const context = getSearchContext(state);
331
+ const compositionConfig = getSearchCompositions(state)[currentComposition];
332
+ if (!compositionConfig) return {};
333
+ const facets = getCompositionFacets(state, currentComposition);
334
+ return {
335
+ ...compositionConfig,
336
+ [context]: facets
337
+ };
338
+ };
339
+
340
+ /** Return filter state for the current (or provided) facet */
265
341
  const getFilters = (state, facet, context = Context.facets, returnType) => {
266
342
  return getImmutableOrJS(state, ['search', context, facet || getCurrent$2(state, context), 'filters'], {}, returnType);
267
343
  };
344
+ const getLocalisedFilterKey = (state, key, language = selectors$1.selectCurrentLanguage(state), facet, context = getSearchContext(state)) => {
345
+ var _filter$i18n;
346
+ const filter = getFilters(state, facet, context, 'js')[key];
347
+ if (filter !== null && filter !== void 0 && (_filter$i18n = filter.i18n) !== null && _filter$i18n !== void 0 && _filter$i18n[language]) {
348
+ return filter.i18n[language];
349
+ }
350
+ return key;
351
+ };
352
+ const getFilterKeyFromLocalised = (state, key, language = selectors$1.selectCurrentLanguage(state), facet, context = getSearchContext(state)) => {
353
+ const filters = getFilters(state, facet, context, 'js');
354
+ for (const [filterKey, filter] of Object.entries(filters)) {
355
+ var _filter$i18n2;
356
+ if (((_filter$i18n2 = filter.i18n) === null || _filter$i18n2 === void 0 ? void 0 : _filter$i18n2[language]) === key) {
357
+ return filterKey;
358
+ }
359
+ }
360
+ return key;
361
+ };
362
+
363
+ /** Return filter state for the current (or provided) facet, excluding filters configured as `renderable: false` */
268
364
  const getRenderableFilters$2 = (state, facet = '', context = Context.facets) => Object.fromEntries(Object.entries(getFilters(state, facet, context, 'js')).filter(([, f = {}]) => typeof f.renderable !== 'boolean' ? true : f.renderable));
269
365
  const getFiltersToLoad = (state, facet, context = Context.facets, returnType) => {
270
366
  const filters = getFilters(state, facet, context, returnType);
@@ -275,19 +371,62 @@ const getFiltersToLoad = (state, facet, context = Context.facets, returnType) =>
275
371
  return loadedFilters.map(([filterKey, isLoaded]) => !isLoaded ? filterKey : null).filter(f => !!f);
276
372
  };
277
373
 
278
- // We lowercase the filter key unless it's an ISO date string where the T must be uppercase
279
- const getSelectedFilters = (state, facet = '', context = Context.facets, returnType) => {
280
- const filters = getFilters(state, facet, context, 'js');
374
+ /** Iterate the selected filters and update their keys to their localized equivalents */
375
+ const localiseSelectedFilterKeys = (selectedFilters, state) => {
376
+ const language = selectors$1.selectCurrentLanguage(state);
377
+ const filters = getFilters(state, getCurrentFacet(state), getSearchContext(state), 'js');
378
+ const localisedSelectedFilters = {};
379
+ for (const [filterKey, selectedValues] of Object.entries(selectedFilters)) {
380
+ var _filter$i18n3;
381
+ const filter = filters[filterKey];
382
+ if (filter !== null && filter !== void 0 && (_filter$i18n3 = filter.i18n) !== null && _filter$i18n3 !== void 0 && _filter$i18n3[language]) {
383
+ const localisedKey = filter.i18n[language];
384
+ localisedSelectedFilters[localisedKey] = selectedValues;
385
+ } else {
386
+ localisedSelectedFilters[filterKey] = selectedValues;
387
+ }
388
+ }
389
+ return localisedSelectedFilters;
390
+ };
391
+
392
+ /** Reduce filters state to a simple object containing all filter keys and the selected values */
393
+ const reduceSelectedFilters = filters => {
281
394
  const selectedFilters = Object.fromEntries(Object.entries(filters).map(([key, filter = {}]) => [key, (filter.items || []).filter(item => !!(item.isSelected || false)).map(item => {
282
395
  const key = (item === null || item === void 0 ? void 0 : item.key) || '';
283
396
  return key;
284
397
  })]));
398
+ return selectedFilters;
399
+ };
400
+
401
+ /** Return keyed object for all filters in the current facet with all selected values for each filter */
402
+ const getSelectedFilters = (state, facet = '', context = Context.facets, returnType) => {
403
+ const filters = getFilters(state, facet, context, 'js');
404
+ const selectedFilters = reduceSelectedFilters(filters);
285
405
  const fromJS = makeFromJS(returnType);
286
406
  return fromJS(selectedFilters);
287
407
  };
408
+
409
+ /** Return keyed object for all _renderable_ filters in the current facet with all selected values for each filter */
410
+ const getRenderableSelectedFilters = (state, facet = '', context = Context.facets) => {
411
+ const filters = getRenderableFilters$2(state, facet, context);
412
+
413
+ // new in CRB4: intended no support for immutable state type
414
+ const selectedFilters = reduceSelectedFilters(filters);
415
+ return selectedFilters;
416
+ };
417
+
418
+ /** A localised version of `getRenderableSelectedFilters` selector */
419
+ const getLocalisedRenderableSelectedFilters = (state, facet = '', context = Context.facets) => {
420
+ const filters = getRenderableSelectedFilters(state, facet, context);
421
+ const localisedFilters = localiseSelectedFilterKeys(filters, state);
422
+ return localisedFilters;
423
+ };
288
424
  const getResults = (state, current = '', context = Context.facets, returnType) => {
289
425
  return getImmutableOrJS(state, ['search', context, current || getCurrent$2(state, context), 'results'], [], returnType);
290
426
  };
427
+ const getResultsInfo = (state, current = '', context = getSearchContext(state)) => {
428
+ return getImmutableOrJS(state, ['search', context, current || getCurrent$2(state, context), 'resultsInfo'], {}, 'js');
429
+ };
291
430
  const getIsInternalPaging = (state, current, context = Context.facets) => {
292
431
  return getImmutableOrJS(state, ['search', context, current || getCurrent$2(state, context), 'queryParams', 'internalPaging'], false);
293
432
  };
@@ -325,6 +464,7 @@ const getTotalCount$1 = (state, current = '', context = Context.facets) => {
325
464
  };
326
465
  const getSearchTerm$2 = state => getImmutableOrJS(state, ['search', 'term']);
327
466
  const getSearchTabs = (state, returnType) => getImmutableOrJS(state, ['search', 'tabs'], [], returnType);
467
+ const getSearchCompositions = state => getImmutableOrJS(state, ['search', 'compositions'], {}, 'js');
328
468
  const getQueryParams = (state, current = '', context = Context.facets) => {
329
469
  return getImmutableOrJS(state, ['search', context, current || getCurrent$2(state, context), 'queryParams'], {}, 'js');
330
470
  };
@@ -338,9 +478,6 @@ const getQueryParameter$2 = ({
338
478
  const getCustomApi = (state, current, context = Context.facets, returnType) => {
339
479
  return getImmutableOrJS(state, ['search', context, current || getCurrent$2(state, context), 'customApi'], null, returnType);
340
480
  };
341
- const getCustomEnv = (state, current, context = Context.facets) => {
342
- return getImmutableOrJS(state, ['search', context, current || getCurrent$2(state, context), 'env']);
343
- };
344
481
  const getTabsAndFacets$1 = (state, returnType) => {
345
482
  const tabs = getSearchTabs(state, 'js');
346
483
  const facets = getFacets(state, 'js');
@@ -381,7 +518,6 @@ const selectFacets = {
381
518
  getCurrent: getCurrentFacet,
382
519
  getCurrentTab: getCurrentTab$1,
383
520
  getCustomApi,
384
- getCustomEnv,
385
521
  getFacet: getFacet$1,
386
522
  getFacetTitles: getFacetTitles$1,
387
523
  getFacets,
@@ -391,6 +527,8 @@ const selectFacets = {
391
527
  getFiltersToLoad,
392
528
  getIsLoaded,
393
529
  getIsLoading: getIsLoading$2,
530
+ /* Localised version of getCurrent */
531
+ getLocalisedCurrent: state => getLocalisedCurrent$2(state, undefined, Context.facets),
394
532
  getPageIndex: getPageIndex$2,
395
533
  getPageIsLoading: getPageIsLoading$2,
396
534
  getPagesLoaded,
@@ -422,6 +560,8 @@ const selectListing = {
422
560
  getFilters: (state, listing = '') => getFilters(state, listing, Context.listings, 'js'),
423
561
  getFiltersToLoad: (state, listing = '') => getFiltersToLoad(state, listing, Context.listings),
424
562
  getListing: getListing$1,
563
+ /* Localised version of getCurrent */
564
+ getLocalisedCurrent: state => getLocalisedCurrent$2(state, undefined, Context.listings),
425
565
  getIsLoaded: state => getIsLoaded(state, Context.listings),
426
566
  getIsLoading: state => getIsLoading$2(state, Context.listings),
427
567
  getPageIndex: (state, listing = '') => getPageIndex$2(state, listing, Context.listings),
@@ -443,23 +583,24 @@ const selectListing = {
443
583
  getTotalCount: (state, listing = '') => getTotalCount$1(state, listing, Context.listings),
444
584
  getSelectedFilters: (state, listing = '') => getSelectedFilters(state, listing, Context.listings, 'js')
445
585
  };
446
- const selectCurrentPath = state => getImmutableOrJS(state, ['routing', 'currentPath']);
447
- const selectCurrentProject = state => getImmutableOrJS(state, ['routing', 'currentProject']);
448
- const selectVersionStatus = state => getImmutableOrJS(state, ['version', 'contensisVersionStatus']);
449
586
 
450
587
  var selectors = /*#__PURE__*/Object.freeze({
451
588
  __proto__: null,
589
+ getComposition: getComposition,
590
+ getCompositionFacets: getCompositionFacets,
452
591
  getCurrent: getCurrent$2,
592
+ getCurrentComposition: getCurrentComposition,
453
593
  getCurrentFacet: getCurrentFacet,
594
+ getCurrentFromLocalised: getCurrentFromLocalised,
454
595
  getCurrentListing: getCurrentListing,
455
596
  getCurrentTab: getCurrentTab$1,
456
597
  getCustomApi: getCustomApi,
457
- getCustomEnv: getCustomEnv,
458
598
  getFacet: getFacet$1,
459
599
  getFacetTitles: getFacetTitles$1,
460
600
  getFacets: getFacets,
461
601
  getFacetsTotalCount: getFacetsTotalCount$1,
462
602
  getFeaturedResults: getFeaturedResults$2,
603
+ getFilterKeyFromLocalised: getFilterKeyFromLocalised,
463
604
  getFilters: getFilters,
464
605
  getFiltersToLoad: getFiltersToLoad,
465
606
  getIsInternalPaging: getIsInternalPaging,
@@ -467,6 +608,10 @@ var selectors = /*#__PURE__*/Object.freeze({
467
608
  getIsLoading: getIsLoading$2,
468
609
  getIsSsr: getIsSsr,
469
610
  getListing: getListing$1,
611
+ getLocalisedCurrent: getLocalisedCurrent$2,
612
+ getLocalisedFacetKey: getLocalisedFacetKey,
613
+ getLocalisedFilterKey: getLocalisedFilterKey,
614
+ getLocalisedRenderableSelectedFilters: getLocalisedRenderableSelectedFilters,
470
615
  getPageIndex: getPageIndex$2,
471
616
  getPageIsLoading: getPageIsLoading$2,
472
617
  getPageSize: getPageSize,
@@ -476,7 +621,10 @@ var selectors = /*#__PURE__*/Object.freeze({
476
621
  getQueryParameter: getQueryParameter$2,
477
622
  getQueryParams: getQueryParams,
478
623
  getRenderableFilters: getRenderableFilters$2,
624
+ getRenderableSelectedFilters: getRenderableSelectedFilters,
479
625
  getResults: getResults,
626
+ getResultsInfo: getResultsInfo,
627
+ getSearchCompositions: getSearchCompositions,
480
628
  getSearchContext: getSearchContext,
481
629
  getSearchTabs: getSearchTabs,
482
630
  getSearchTerm: getSearchTerm$2,
@@ -485,275 +633,29 @@ var selectors = /*#__PURE__*/Object.freeze({
485
633
  getTabFacets: getTabFacets$1,
486
634
  getTabsAndFacets: getTabsAndFacets$1,
487
635
  getTotalCount: getTotalCount$1,
488
- selectCurrentPath: selectCurrentPath,
489
- selectCurrentProject: selectCurrentProject,
490
636
  selectFacets: selectFacets,
491
- selectListing: selectListing,
492
- selectVersionStatus: selectVersionStatus
637
+ selectListing: selectListing
493
638
  });
494
639
 
495
- const now = () => {
496
- if (typeof window == 'undefined') {
497
- return Date.now();
498
- }
499
- return window.performance.now();
500
- };
501
-
502
- const getClientConfig = (project, env) => {
503
- let config = DELIVERY_API_CONFIG; /* global DELIVERY_API_CONFIG */
504
- if (project) {
505
- config.projectId = project;
506
- }
507
- if (typeof window != 'undefined' && PROXY_DELIVERY_API /* global PROXY_DELIVERY_API */) {
508
- // ensure a relative url is used to bypass the need for CORS (separate OPTIONS calls)
509
- config.rootUrl = env || '';
510
- config.responseHandler = {
511
- 404: () => null
512
- };
513
- }
514
- return config;
515
- };
516
- class CacheNode {
517
- constructor(key, value) {
518
- this.key = key;
519
- this.value = value;
520
- this.next = null;
521
- this.prev = null;
522
- }
523
- }
524
- class LruCache {
525
- constructor(limit = 100) {
526
- this.map = {};
527
- this.head = null;
528
- this.tail = null;
529
- this.limit = limit || 100;
530
- this.size = 0;
531
- }
532
- get(key) {
533
- if (this.map[key]) {
534
- let value = this.map[key].value;
535
- let node = new CacheNode(key, value);
536
- this.remove(key);
537
- this.setHead(node);
538
- return value;
539
- }
540
- }
541
- set(key, value) {
542
- let node = new CacheNode(key, value);
543
- if (this.map[key]) {
544
- this.remove(key);
545
- } else {
546
- if (this.size >= this.limit) {
547
- delete this.map[this.tail.key];
548
- this.size--;
549
- this.tail = this.tail.prev;
550
- this.tail.next = null;
551
- }
552
- }
553
- this.setHead(node);
554
- }
555
- setHead(node) {
556
- node.next = this.head;
557
- node.prev = null;
558
- if (this.head) {
559
- this.head.prev = node;
560
- }
561
- this.head = node;
562
- if (!this.tail) {
563
- this.tail = node;
564
- }
565
- this.size++;
566
- this.map[node.key] = node;
567
- }
568
- remove(key) {
569
- let node = this.map[key];
570
- if (node.prev) {
571
- node.prev.next = node.next;
572
- } else {
573
- this.head = node.next;
574
- }
575
- if (node.next) {
576
- node.next.prev = node.prev;
577
- } else {
578
- this.tail = node.prev;
579
- }
580
- delete this.map[key];
581
- this.size--;
582
- }
583
- }
584
- class CachedSearch {
585
- constructor() {
586
- this.cache = new LruCache();
587
- this.taxonomyLookup = {};
588
- }
589
- search(query, linkDepth, project, env) {
590
- const client = contensisDeliveryApi.Client.create(getClientConfig(project, env));
591
- return this.request(project + JSON.stringify(query) + linkDepth.toString(), () => client.entries.search(query, linkDepth));
592
- }
593
- getTaxonomyNodeByPath(path, project, env) {
594
- const client = contensisDeliveryApi.Client.create(getClientConfig(project, env));
595
- return this.request(`[TAXONOMY NODE] ${path}`, () => client.taxonomy.getNodeByPath({
596
- path: path,
597
- order: 'defined',
598
- childDepth: 2
599
- }).then(node => this.extendTaxonomyNode(node)));
600
- }
601
- request(key, execute) {
602
- if (!this.cache.get(key) || typeof window == 'undefined') {
603
- let promise = execute();
604
- this.cache.set(key, promise);
605
- promise.catch(() => {
606
- this.cache.remove(key);
607
- });
608
- }
609
- return this.cache.get(key);
610
- }
611
- extendTaxonomyNode(node) {
612
- let id = this.getTaxonomyId(node);
613
- this.taxonomyLookup[id] = node.key;
614
- return {
615
- ...node,
616
- id,
617
- children: node.children ? node.children.map(n => this.extendTaxonomyNode(n)) : null
618
- };
619
- }
620
- getTaxonomyId(node) {
621
- if (node.key) {
622
- let parts = node.key.split('/');
623
- return parts[parts.length - 1];
624
- }
625
- return '';
626
- }
627
- fetch(uri, opts = {}) {
628
- return this.request(`[FETCH] ${uri} ${JSON.stringify(opts)}`, () => fetch(uri, opts));
629
- }
630
- }
631
- const cachedSearch = new CachedSearch();
632
-
633
- function fixFreeTextForElastic(s) {
634
- const illegalChars = ['>', '<', '=', '|', '!', '{', '}', '[', ']', '^', '~', '*', '?', ':', '\\', '/'];
635
- const illegalRegEx = new RegExp(illegalChars.map(c => '\\' + c).join('|'), 'g');
636
- s = s.replace(illegalRegEx, '');
637
- // s = s.replace(encodedRegEx, ''); // (m) => '\\\\' + m);
638
-
639
- return s;
640
- }
641
- /** `convertKeyForAggregation` and `parseKeyForAggregation` exists to prevent an
642
- * auto-generated aggregation using a reserved keyword because Elasticsearch has a list of
643
- * reserved keywords when it parses the response:
644
- * `'location' is one of the reserved aggregation keywords we use a heuristics based
645
- * response parser and using these reserved keywords could throw its heuristics off
646
- * course. We are working on a solution in Elasticsearch itself to make the response
647
- * parseable. For now these are all the reserved keywords: after_key, _as_string,
648
- * bg_count, bottom_right, bounds, buckets, count, doc_count, doc_count_error_upper_bound,
649
- * fields, from, top, type, from_as_string, hits, key, key_as_string, keys, location,
650
- * max_score, meta, min, min_length, score, sum_other_doc_count, to, to_as_string, top_left,
651
- * total, value, value_as_string, values, geometry, properties`
652
- */
653
- const convertKeyForAggregation = key => `sf_${key}`;
654
- const convertFieldIdForAggregation = fieldId => fieldId.replaceAll('[]', '');
655
- const timedSearch = async (query, linkDepth = 0, projectId, env) => {
656
- if (!query) return null;
657
- let duration = 0;
658
- const start = now();
659
- const payload = await cachedSearch.search(query, linkDepth, projectId, env);
660
- const end = now();
661
- duration = Number((end - start).toFixed(2));
662
- return {
663
- duration,
664
- payload
665
- };
666
- };
667
- const getItemsFromResult = result => {
668
- const {
669
- payload
670
- } = result || {};
671
- if (payload) {
672
- if (Array.isArray(payload)) return payload;
673
- if (Array.isArray(payload.items)) return payload.items;
674
- return payload;
675
- }
676
- return [];
677
- };
678
- const extractQuotedPhrases = searchTerm => {
679
- const pattern = new RegExp(/(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')/gm);
680
- return (searchTerm.match(pattern) || []).map(match => match.replace(/"/g, ''));
681
- };
682
- const buildUrl = (route, params) => {
683
- const qs = queryString.stringify(params);
684
- const path = qs ? `${route}${route.includes('?') ? '&' : '?'}${qs}` : route;
685
- return path;
686
- };
687
-
688
- /**
689
- * Returns all params from the current route query string or static route
690
- * Supply static route argument if reading parameters from the route path
691
- * Supply location argument for the params to be read in SSR
692
- * @param staticRoute Matched static route from react-router 5 or 6
693
- * @param location location object containing at least pathname and search
694
- * @returns Keyed params object
695
- */
696
- const routeParams = (staticRoute, location) => {
697
- var _staticRoute$match;
698
- // match.params is react-router-config/react-router@5 style
699
- // params is supplied with RouteObject in react-router@6
700
- const pathParams = (staticRoute === null || staticRoute === void 0 || (_staticRoute$match = staticRoute.match) === null || _staticRoute$match === void 0 ? void 0 : _staticRoute$match.params) || (staticRoute === null || staticRoute === void 0 ? void 0 : staticRoute.params) || {};
701
- const queryParams = queryString.parse(typeof window !== 'undefined' ? window.location.search : (location === null || location === void 0 ? void 0 : location.search) || '');
702
- return {
703
- ...pathParams,
704
- ...queryParams
705
- };
706
- };
707
- const callCustomApi = async (customApi, filters) => {
708
- const apiUri = customApi.uri || '';
709
- let uri = buildUrl(apiUri, filters);
710
- if (!uri) throw new Error('uri is required to use customApi');
711
- if (typeof window == 'undefined') {
712
- if (!uri.startsWith('http')) uri = `http://localhost:3001${uri}`;
713
- const response = await fetch(uri);
714
- return await response.json();
715
- }
716
- const response = await cachedSearch.fetch(uri);
717
- return await response.clone().json();
718
- };
719
- const removeEmptyAttributes = obj => {
720
- Object.entries(obj).forEach(([key, val]) => val && typeof val === 'object' && removeEmptyAttributes(val) || (typeof val === 'undefined' || val === null || val === '') && delete obj[key]);
721
- return obj;
722
- };
723
- const toArray = (obj, seperator = ',') => typeof obj === 'undefined' || obj === null ? obj : Array.isArray(obj) ? obj : obj.split(seperator);
724
-
725
- // assumes array elements are primitive types
726
- const areArraysEqualSets = (a1, a2) => {
727
- const superSet = {};
728
- for (const ai of a1) {
729
- const e = ai + typeof ai;
730
- superSet[e] = 1;
731
- }
732
- for (const ai of a2) {
733
- const e = ai + typeof ai;
734
- if (!superSet[e]) {
735
- return false;
736
- }
737
- superSet[e] = 2;
738
- }
739
- for (const e in superSet) {
740
- if (superSet[e] === 1) {
741
- return false;
742
- }
743
- }
744
- return true;
745
- };
746
-
747
640
  const searchUriTemplate = {
748
641
  path: ({
749
642
  state,
750
643
  facet
751
644
  }) => {
645
+ var _staticRoute$route;
752
646
  const context = getSearchContext(state);
753
- const currentPath = selectCurrentPath(state) || '/search';
754
- if (context !== 'listings') {
755
- const currentFacet = facet || getCurrentFacet(state);
647
+ const currentPath = selectors$2.selectCurrentPath(state) || '/search';
648
+ const staticRoute = selectors$2.selectStaticRoute(state);
649
+ const hasFacetRouteParam = staticRoute === null || staticRoute === void 0 || (_staticRoute$route = staticRoute.route) === null || _staticRoute$route === void 0 || (_staticRoute$route = _staticRoute$route.path) === null || _staticRoute$route === void 0 ? void 0 : _staticRoute$route.includes(`/:${context === 'facets' ? 'facet' : 'listingType'}`);
650
+
651
+ // if (context !== 'listings') {
652
+ if (hasFacetRouteParam) {
653
+ const currentFacet = getLocalisedFacetKey(state, facet) || facet || getLocalisedCurrent$2(state);
756
654
  const filters = getSelectedFilters(state, facet, context);
655
+ // TODO: This only looking for a filter called contentTypeId
656
+ // feels a bit useless and only really serves as an example.
657
+ // We could expand this in future to be configured with the filter or the route
658
+ // e.g. look for a route param matching the filter key in the static route
757
659
  const currentFilter = filters.contentTypeId;
758
660
 
759
661
  // Check if we have a filter first
@@ -771,17 +673,33 @@ const searchUriTemplate = {
771
673
  pageIndex,
772
674
  pageSize
773
675
  }) => {
774
- const searchContext = getSearchContext(state);
676
+ var _staticRoute$route2;
677
+ const context = getSearchContext(state);
678
+ const staticRoute = selectors$2.selectStaticRoute(state);
679
+ // Some listing routes may not have the listingType or facet as a route param
680
+ // include it as a query param to ensure the correct listing/facet is set or updated
681
+ const hasFacetRouteParam = staticRoute === null || staticRoute === void 0 || (_staticRoute$route2 = staticRoute.route) === null || _staticRoute$route2 === void 0 || (_staticRoute$route2 = _staticRoute$route2.path) === null || _staticRoute$route2 === void 0 ? void 0 : _staticRoute$route2.includes(`/:${context === 'facets' ? 'facet' : 'listingType'}`);
682
+ const currentFacet = getLocalisedFacetKey(state, facet) || facet || getLocalisedCurrent$2(state);
683
+ const facetQuery = !hasFacetRouteParam && currentFacet ? {
684
+ [context === 'listings' ? 'listingType' : 'facet']: currentFacet
685
+ } : {};
686
+
775
687
  // Lose stateFilters and currentSearch if a new
776
688
  // term is passed via an argument
777
- const stateFilters = term ? {} : Object.fromEntries(Object.entries(getSelectedFilters(state, facet, searchContext, 'js')).map(([k, f]) => [k, f === null || f === void 0 ? void 0 : f.join(',')]));
689
+ const stateFilters = term ? {} : Object.fromEntries(Object.entries(getLocalisedRenderableSelectedFilters(state, facet, context)).map(([k, f]) => [k, f === null || f === void 0 ? void 0 : f.join(',')]));
778
690
  const currentSearch = !term && getImmutableOrJS(state, ['routing', 'location', 'search']);
779
- const currentQs = removeEmptyAttributes(queryString.parse(currentSearch));
780
- if (orderBy) currentQs.orderBy = orderBy;
691
+ const currentQs = util.removeEmptyAttributes(queryString.parse(currentSearch));
692
+
693
+ // An argument is provided with the updated value
694
+ // when the relevant action has been triggered
695
+ if (typeof orderBy !== 'undefined') currentQs.orderBy = orderBy;
781
696
  const searchTerm = getSearchTerm$2(state);
782
697
  // Use Immutable's merge to merge the stateFilters with any current Qs
783
698
  // to build the new Qs.
784
- const mergedSearch = removeEmptyAttributes(merge__default.default(currentQs, stateFilters));
699
+ const mergedSearch = util.removeEmptyAttributes(merge__default.default(currentQs, {
700
+ ...facetQuery,
701
+ ...stateFilters
702
+ }));
785
703
 
786
704
  // We must handle term === '' separately, because this means the user has cleared the search term
787
705
  // If this is true, we don't want to fall back to the existing search term. We only want to do that if the
@@ -817,6 +735,7 @@ const {
817
735
  getFacetTitles,
818
736
  getFeaturedResults: getFeaturedResults$1,
819
737
  getIsLoading: getIsLoading$1,
738
+ getLocalisedCurrent: getLocalisedCurrent$1,
820
739
  getPageIndex: getPageIndex$1,
821
740
  getPageIsLoading: getPageIsLoading$1,
822
741
  getQueryParameter: getQueryParameter$1,
@@ -828,6 +747,8 @@ const {
828
747
  getTotalCount
829
748
  } = selectFacets;
830
749
  const makeSelectFacetsProps = () => reselect.createSelector(state => state, (_, mappers) => mappers, (state, mappers) => ({
750
+ composition: getComposition(state),
751
+ currentComposition: getCurrentComposition(state),
831
752
  currentFacet: getCurrent$1(state),
832
753
  currentPageIndex: getPageIndex$1(state),
833
754
  currentTabIndex: getCurrentTab(state),
@@ -838,10 +759,11 @@ const makeSelectFacetsProps = () => reselect.createSelector(state => state, (_,
838
759
  featured: getFeaturedResults$1(state),
839
760
  filters: getRenderableFilters$1(state),
840
761
  isLoading: getIsLoading$1(state),
762
+ localisedCurrent: getLocalisedCurrent$1(state),
841
763
  pageIsLoading: getPageIsLoading$1(state),
842
764
  paging: getPaging(state, '', Context.facets, 'js'),
843
765
  results: getResults(state, '', Context.facets, 'js'),
844
- resultsInfo: mappers && typeof mappers.resultsInfo === 'function' && mappers.resultsInfo(state),
766
+ resultsInfo: typeof (mappers === null || mappers === void 0 ? void 0 : mappers.resultsInfo) === 'function' && mappers.resultsInfo(state) || getResultsInfo(state),
845
767
  searchTerm: getSearchTerm$1(state),
846
768
  searchTotalCount: getSearchTotalCount(state),
847
769
  selectedFilters: getSelectedFilters(state, '', Context.facets, 'js'),
@@ -870,6 +792,8 @@ const useFacets = ({
870
792
  updateSortOrder: orderBy => dispatch(withMappers(updateSortOrder$1(orderBy), m))
871
793
  };
872
794
  const {
795
+ composition,
796
+ currentComposition,
873
797
  currentFacet,
874
798
  currentPageIndex,
875
799
  currentTabIndex,
@@ -880,6 +804,7 @@ const useFacets = ({
880
804
  featured,
881
805
  filters,
882
806
  isLoading,
807
+ localisedCurrent,
883
808
  paging,
884
809
  pageIsLoading,
885
810
  results,
@@ -892,6 +817,8 @@ const useFacets = ({
892
817
  totalCount
893
818
  } = reactRedux.useSelector(state => selectListingProps(state, m));
894
819
  return {
820
+ composition,
821
+ currentComposition,
895
822
  currentFacet,
896
823
  currentPageIndex,
897
824
  currentTabIndex,
@@ -902,6 +829,7 @@ const useFacets = ({
902
829
  featured,
903
830
  filters,
904
831
  isLoading,
832
+ localisedCurrent,
905
833
  paging,
906
834
  pageIsLoading,
907
835
  results,
@@ -921,6 +849,7 @@ const {
921
849
  getFeaturedResults,
922
850
  getIsLoading,
923
851
  getListing,
852
+ getLocalisedCurrent,
924
853
  getPageIndex,
925
854
  getPageIsLoading,
926
855
  getQueryParameter,
@@ -928,16 +857,19 @@ const {
928
857
  getSearchTerm
929
858
  } = selectListing;
930
859
  const makeSelectListingProps = () => reselect.createSelector(state => state, (_, mappers) => mappers, (state, mappers) => ({
860
+ composition: getComposition(state),
861
+ currentComposition: getCurrentComposition(state),
931
862
  currentListing: getCurrent(state),
932
863
  currentPageIndex: getPageIndex(state),
933
- listing: getListing(state),
934
864
  featured: getFeaturedResults(state),
935
865
  filters: getRenderableFilters(state),
936
866
  isLoading: getIsLoading(state),
867
+ listing: getListing(state),
868
+ localisedCurrent: getLocalisedCurrent(state),
937
869
  pageIsLoading: getPageIsLoading(state),
938
870
  paging: getPaging(state, '', Context.listings, 'js'),
939
871
  results: getResults(state, '', Context.listings, 'js'),
940
- resultsInfo: mappers && typeof mappers.resultsInfo === 'function' && mappers.resultsInfo(state),
872
+ resultsInfo: typeof mappers.resultsInfo === 'function' && mappers.resultsInfo(state) || getResultsInfo(state),
941
873
  searchTerm: getSearchTerm(state),
942
874
  selectedFilters: getSelectedFilters(state, '', Context.listings, 'js'),
943
875
  sortOrder: getQueryParameter({
@@ -962,12 +894,15 @@ const useListing = ({
962
894
  updateSortOrder: orderBy => dispatch(withMappers(updateSortOrder$1(orderBy), m))
963
895
  };
964
896
  const {
897
+ composition,
898
+ currentComposition,
965
899
  currentListing,
966
900
  currentPageIndex,
967
901
  featured,
968
902
  filters,
969
903
  isLoading,
970
904
  listing,
905
+ localisedCurrent,
971
906
  paging,
972
907
  pageIsLoading,
973
908
  results,
@@ -977,12 +912,15 @@ const useListing = ({
977
912
  sortOrder
978
913
  } = reactRedux.useSelector(state => selectListingProps(state, m));
979
914
  return {
915
+ composition,
916
+ currentComposition,
980
917
  currentListing,
981
918
  currentPageIndex,
982
919
  featured,
983
920
  filters,
984
921
  isLoading,
985
922
  listing,
923
+ localisedCurrent,
986
924
  pageIsLoading,
987
925
  paging,
988
926
  results,
@@ -995,11 +933,53 @@ const useListing = ({
995
933
  };
996
934
  };
997
935
 
936
+ class CachedTaxonomyLookup {
937
+ constructor() {
938
+ this.cache = new ContensisDeliveryApi.LruCache();
939
+ this.taxonomyLookup = {};
940
+ }
941
+ getTaxonomyNodeByPath(path, project, env) {
942
+ const client = contensisDeliveryApi.Client.create(ContensisDeliveryApi.getClientConfig(project, env));
943
+ return this.request(`[TAXONOMY] ${path}`, () => client.taxonomy.getNodeByPath({
944
+ path: path,
945
+ order: 'defined',
946
+ childDepth: 2
947
+ }).then(node => this.extendTaxonomyNode(node)));
948
+ }
949
+ request(key, execute) {
950
+ if (!this.cache.get(key) || typeof window == 'undefined') {
951
+ let promise = execute();
952
+ this.cache.set(key, promise);
953
+ promise.catch(() => {
954
+ this.cache.remove(key);
955
+ });
956
+ }
957
+ return this.cache.get(key);
958
+ }
959
+ extendTaxonomyNode(node) {
960
+ let id = this.getTaxonomyId(node);
961
+ this.taxonomyLookup[id] = node.key;
962
+ return {
963
+ ...node,
964
+ id,
965
+ children: node.children ? node.children.map(n => this.extendTaxonomyNode(n)) : null
966
+ };
967
+ }
968
+ getTaxonomyId(node) {
969
+ if (node.key) {
970
+ let parts = node.key.split('/');
971
+ return parts[parts.length - 1];
972
+ }
973
+ return '';
974
+ }
975
+ }
976
+
977
+ /** @deprecated Taxonomy is deprecated in Contensis, code remains
978
+ * to support any legacy implementations using Taxonomy in their search */
979
+ const cachedTaxonomyLookup = new CachedTaxonomyLookup();
980
+
998
981
  const DataFormats = {
999
- asset: 'asset',
1000
- entry: 'entry',
1001
- webpage: 'webpage'
1002
- };
982
+ entry: 'entry'};
1003
983
  const FilterExpressionTypes = {
1004
984
  contentType: 'contentType',
1005
985
  field: 'field'
@@ -1034,16 +1014,20 @@ const fieldExpression = (field, value, operator = 'equalTo', weight, fuzzySearch
1034
1014
  const contentTypeIdExpression = (contentTypeIds, webpageTemplates, assetTypes) => {
1035
1015
  const expressions = [];
1036
1016
  if (!contentTypeIds && !webpageTemplates && !assetTypes) return expressions;
1037
- if (contentTypeIds && contentTypeIds.length > 0) {
1038
- expressions.push(...dataFormatExpression(contentTypeIds, DataFormats.entry));
1039
- }
1040
- if (webpageTemplates && webpageTemplates.length > 0) {
1041
- expressions.push(...dataFormatExpression(webpageTemplates, DataFormats.webpage));
1017
+ const ids = [...new Set([...(contentTypeIds || []), ...(webpageTemplates || []), ...(assetTypes || [])])];
1018
+
1019
+ /**
1020
+ * We have an array of contentTypeIds some may be prefixed with a "!"
1021
+ * to indicate this is a "not" expression
1022
+ */
1023
+ const withContentTypeIds = ids.filter(c => !c.startsWith('!'));
1024
+ const notContentTypeIds = ids.filter(c => c.startsWith('!')).map(id => id.substring(1));
1025
+ if (withContentTypeIds.length > 0) {
1026
+ expressions.push(...fieldExpression(Fields.sys.contentTypeId, withContentTypeIds));
1042
1027
  }
1043
- if (assetTypes && assetTypes.length > 0) {
1044
- expressions.push(...dataFormatExpression(assetTypes, DataFormats.asset));
1028
+ if (notContentTypeIds.length > 0) {
1029
+ expressions.push(contensisCoreApi.Op.not(fieldExpression(Fields.sys.contentTypeId, notContentTypeIds)[0]));
1045
1030
  }
1046
- if (expressions.length > 1) return [contensisCoreApi.Op.or(...expressions)];
1047
1031
  return expressions;
1048
1032
  };
1049
1033
  const filterExpressions = (filters, isOptional = false) => {
@@ -1066,6 +1050,9 @@ const filterExpressions = (filters, isOptional = false) => {
1066
1050
  });
1067
1051
  return expressions;
1068
1052
  };
1053
+
1054
+ /** @deprecated since v4 - contentTypeIdExpression produces a simpler more efficient query
1055
+ * now and negates the need for supplying `sys.dataFormat` with `sys.contentTypeId` */
1069
1056
  const dataFormatExpression = (contentTypeIds, dataFormat = DataFormats.entry) => {
1070
1057
  if (contentTypeIds && contentTypeIds.length > 0) {
1071
1058
  /**
@@ -1176,7 +1163,6 @@ const between = (field, value) => {
1176
1163
  const [minimum, maximum] = valArr;
1177
1164
  return contensisCoreApi.Op.between(field, minimum, maximum);
1178
1165
  } else {
1179
- // eslint-disable-next-line no-console
1180
1166
  console.log(`[search] You have supplied only one value to a "between" operator which must have two values. Your supplied value "${valArr.length && valArr[0]}" has been discarded.`);
1181
1167
  return false;
1182
1168
  }
@@ -1193,7 +1179,6 @@ const distanceWithin = (field, value) => {
1193
1179
  const [lat, lon] = valArr;
1194
1180
  return contensisCoreApi.Op.distanceWithin(field, Number(lat), Number(lon), (valArr === null || valArr === void 0 ? void 0 : valArr[2]) || '10mi');
1195
1181
  } else {
1196
- // eslint-disable-next-line no-console
1197
1182
  console.log(`[search] You have supplied only one value to a "distanceWithin" operator which must be made up of "lat,lon,distance". Your supplied value "${valArr.length && valArr[0]}" has been discarded.`);
1198
1183
  return false;
1199
1184
  }
@@ -1260,7 +1245,7 @@ const makeJsExpression = (operator, field, value) => operator === 'freeText' ||
1260
1245
  const termExpressions = (searchTerm, weightedSearchFields, fuzzySearch, omitSearchFields = []) => {
1261
1246
  if (searchTerm && weightedSearchFields && weightedSearchFields.length > 0) {
1262
1247
  // Extract any phrases in quotes to array
1263
- const quotedPhrases = extractQuotedPhrases(searchTerm);
1248
+ const quotedPhrases = util.extractQuotedPhrases(searchTerm);
1264
1249
 
1265
1250
  // Modify the search term to remove any quoted phrases to leave any remaining terms
1266
1251
  let modifiedSearchTerm = searchTerm;
@@ -1270,8 +1255,8 @@ const termExpressions = (searchTerm, weightedSearchFields, fuzzySearch, omitSear
1270
1255
  const operators = [];
1271
1256
 
1272
1257
  // Helper functions to generate Op expressions
1273
- const containsOp = (f, term) => fieldExpression(f.fieldId, fixFreeTextForElastic(term), 'contains', f.weight);
1274
- const freeTextOp = (f, term) => fieldExpression(f.fieldId, fixFreeTextForElastic(term), 'freeText', f.weight, fuzzySearch);
1258
+ const containsOp = (f, term) => fieldExpression(f.fieldId, util.fixFreeTextForElastic(term), 'contains', f.weight);
1259
+ const freeTextOp = (f, term) => fieldExpression(f.fieldId, util.fixFreeTextForElastic(term), 'freeText', f.weight, fuzzySearch);
1275
1260
 
1276
1261
  // For each weighted search field
1277
1262
  weightedSearchFields.forEach(wsf => {
@@ -1346,10 +1331,10 @@ var expressions = /*#__PURE__*/Object.freeze({
1346
1331
  termExpressions: termExpressions
1347
1332
  });
1348
1333
 
1349
- const filterQuery = (contentTypeIds, versionStatus, customWhere) => {
1350
- const query = new contensisCoreApi.Query(...[...contentTypeIdExpression(contentTypeIds), ...defaultExpressions(versionStatus), ...customWhereExpressions(customWhere)]);
1334
+ const filterQuery = (contentTypeIds, languages, versionStatus, customWhere, pageSize = 100) => {
1335
+ const query = new contensisCoreApi.Query(...[...contentTypeIdExpression(contentTypeIds), ...languagesExpression(languages), ...defaultExpressions(versionStatus), ...customWhereExpressions(customWhere)]);
1351
1336
  query.orderBy = contensisCoreApi.OrderBy.asc(Fields.entryTitle);
1352
- query.pageSize = 100;
1337
+ query.pageSize = pageSize;
1353
1338
  return query;
1354
1339
  };
1355
1340
  const searchQuery = ({
@@ -5075,19 +5060,65 @@ const facetTemplate = {
5075
5060
  action,
5076
5061
  featuredResult,
5077
5062
  state
5078
- }) => mapEntriesToSearchResults(action, getItemsFromResult(featuredResult), state),
5063
+ }) => mapEntriesToSearchResults(action, util.getItemsFromResult(featuredResult), state),
5079
5064
  filters: ({
5080
5065
  result,
5081
5066
  state,
5082
5067
  action
5083
5068
  }) => {
5084
- const aggregations = 'aggregations' in result.payload ? result.payload.aggregations : undefined;
5069
+ const aggregations = result.payload && 'aggregations' in result.payload ? result.payload.aggregations : undefined;
5085
5070
  if (!aggregations) return {};
5086
5071
 
5087
- // Handle aggregations client-side where the filter items have loaded before the results containing the aggregations
5072
+ // Handle aggregations client-side where the filter items have loaded
5073
+ // before the results containing the aggregations
5088
5074
  const filters = cloneDeep(getFilters(state, action.facet, action.context, 'js'));
5089
- for (const [filterKey, filter] of Object.entries(filters)) {
5090
- const aggregation = aggregations[convertKeyForAggregation(filterKey)];
5075
+ for (const filter of Object.values(filters)) {
5076
+ let aggregation = {};
5077
+ if (typeof filter.fieldId === 'string') {
5078
+ aggregation = aggregations[util.convertKeyForAggregation(filter.fieldId)] || {};
5079
+ } else if (Array.isArray(filter.fieldId)) {
5080
+ for (const fieldId of filter.fieldId) {
5081
+ aggregation = merge__default.default(aggregation, aggregations[util.convertKeyForAggregation(fieldId)] || {});
5082
+ }
5083
+ }
5084
+ // Populate filter items from aggregations for example tag fields
5085
+ if (filter.aggregations) {
5086
+ // Use supplied aggregations instead of field aggregations
5087
+ if (typeof filter.aggregations === 'string') {
5088
+ aggregation = aggregations[util.convertKeyForAggregation(filter.aggregations)] || {};
5089
+ } else if (Array.isArray(filter.aggregations)) {
5090
+ aggregation = {};
5091
+ for (const fieldId of filter.aggregations) {
5092
+ aggregation = merge__default.default(aggregation, aggregations[util.convertKeyForAggregation(fieldId)] || {});
5093
+ }
5094
+ }
5095
+ // Start with existing items that are not in the aggregation
5096
+ const existingItemsNotInAggregation = (filter.items || []).filter(item => !(item.key in (aggregation || {}))).map(item => {
5097
+ delete item.aggregate;
5098
+ return item;
5099
+ });
5100
+
5101
+ // Map aggregation entries to filter items
5102
+ const aggregationItems = Object.entries(aggregation || {}).map(([key, aggregate]) => {
5103
+ var _filter$items;
5104
+ const existing = ((_filter$items = filter.items) === null || _filter$items === void 0 ? void 0 : _filter$items.find(item => item.key === key)) || {};
5105
+ return {
5106
+ key,
5107
+ title: (existing === null || existing === void 0 ? void 0 : existing.title) || `${key[0].toUpperCase()}${key.slice(1)}`,
5108
+ isSelected: !!(existing !== null && existing !== void 0 && existing.isSelected),
5109
+ aggregate
5110
+ };
5111
+ });
5112
+
5113
+ // Combine existing items not in aggregation with aggregation items
5114
+ filter.items = [...existingItemsNotInAggregation, ...aggregationItems].sort((a, b) => (a.title || a.key).localeCompare(b.title || b.key));
5115
+ continue;
5116
+ }
5117
+
5118
+ // Update aggregation counts on existing filter items
5119
+ // In the context of a pre-loaded facet, the filter items will
5120
+ // not have been loaded yet, so we need to check again when
5121
+ // the filter items load and populate the aggregate counts then as well
5091
5122
  for (const filterItem of filter.items || []) {
5092
5123
  if (!aggregation) delete filterItem.aggregate;else {
5093
5124
  const aggregate = aggregation[filterItem.key.toLowerCase()];
@@ -5144,7 +5175,7 @@ const facetTemplate = {
5144
5175
  pagesLoaded,
5145
5176
  prevPageIndex
5146
5177
  } = action.queryParams;
5147
- const results = mapEntriesToSearchResults(action, getItemsFromResult(result), state);
5178
+ const results = mapEntriesToSearchResults(action, util.getItemsFromResult(result), state);
5148
5179
  if (!loadMorePaging) return results;
5149
5180
 
5150
5181
  // add a _pageIndex property to the returned results to help us later
@@ -5168,6 +5199,7 @@ const facetTemplate = {
5168
5199
  },
5169
5200
  preload: 'action.preload',
5170
5201
  ogState: 'action.ogState',
5202
+ state: 'state',
5171
5203
  debug: 'action.debug'
5172
5204
  };
5173
5205
  const filterTemplate = {
@@ -5187,7 +5219,7 @@ const filterTemplate = {
5187
5219
  selectedKeys,
5188
5220
  mapper,
5189
5221
  facet,
5190
- filterKey
5222
+ filter
5191
5223
  }) => {
5192
5224
  // Handle taxonomy filter items
5193
5225
  if (payload && 'children' in payload) {
@@ -5200,10 +5232,18 @@ const filterTemplate = {
5200
5232
  }
5201
5233
 
5202
5234
  // Handle entries-based filter items
5203
- if (payload && 'items' in payload) {
5204
- var _facet$aggregations;
5235
+ if (payload && 'items' in payload && filter.fieldId) {
5236
+ var _facet$aggregations2;
5205
5237
  // Handle aggregations from SSR where the results containing the aggregations have loaded before the filter items
5206
- const aggregation = (_facet$aggregations = facet.aggregations) === null || _facet$aggregations === void 0 ? void 0 : _facet$aggregations[convertKeyForAggregation(filterKey)];
5238
+ const aggregation = Array.isArray(filter.fieldId) ? filter.fieldId.reduce((agg, fieldId) => {
5239
+ var _facet$aggregations;
5240
+ const fieldAggregations = ((_facet$aggregations = facet.aggregations) === null || _facet$aggregations === void 0 ? void 0 : _facet$aggregations[util.convertKeyForAggregation(fieldId)]) || {};
5241
+ // Accumulate numeric values for matching keys from previous counted fields
5242
+ for (const [key, value] of Object.entries(fieldAggregations)) {
5243
+ agg[key] = (agg[key] || 0) + value;
5244
+ }
5245
+ return agg;
5246
+ }, {}) : (_facet$aggregations2 = facet.aggregations) === null || _facet$aggregations2 === void 0 ? void 0 : _facet$aggregations2[util.convertKeyForAggregation(filter.fieldId)];
5207
5247
  const items = payload.items.map(item => {
5208
5248
  var _item$sys, _item$sys2;
5209
5249
  item.isSelected = selectedKeys === null || selectedKeys === void 0 ? void 0 : selectedKeys.includes(item === null || item === void 0 || (_item$sys = item.sys) === null || _item$sys === void 0 ? void 0 : _item$sys.id);
@@ -5211,7 +5251,7 @@ const filterTemplate = {
5211
5251
  if (typeof aggregate === 'number') item.aggregate = aggregate;
5212
5252
  return item;
5213
5253
  });
5214
- return mapper === null || mapper === void 0 ? void 0 : mapper(items);
5254
+ return (mapper === null || mapper === void 0 ? void 0 : mapper(items)) || [];
5215
5255
  }
5216
5256
  return [];
5217
5257
  }
@@ -5268,10 +5308,22 @@ const queryParamsTemplate = {
5268
5308
  } = root;
5269
5309
  const stateFilters = getFilters(state, facet, context, 'js');
5270
5310
  const aggregations = {};
5271
- for (const [filterKey, filter] of Object.entries(stateFilters)) {
5272
- if (filter.fieldId && !Array.isArray(filter.fieldId)) {
5273
- aggregations[convertKeyForAggregation(filterKey)] = {
5274
- field: convertFieldIdForAggregation(filter.fieldId),
5311
+ for (const filter of Object.values(stateFilters)) {
5312
+ if (Array.isArray(filter.fieldId)) {
5313
+ for (const id of filter.fieldId) {
5314
+ const field = util.cleanseFieldIdForAggregation(id);
5315
+ const aggregationKey = util.convertKeyForAggregation(field);
5316
+ if (!aggregations[aggregationKey]) {
5317
+ aggregations[aggregationKey] = {
5318
+ field,
5319
+ size: 100
5320
+ };
5321
+ }
5322
+ }
5323
+ } else if (filter.fieldId) {
5324
+ const field = util.cleanseFieldIdForAggregation(filter.fieldId);
5325
+ aggregations[util.convertKeyForAggregation(field)] = {
5326
+ field,
5275
5327
  size: 100
5276
5328
  };
5277
5329
  }
@@ -5285,11 +5337,6 @@ const queryParamsTemplate = {
5285
5337
  contentTypeIds: root => getQueryParameter$2(root, 'contentTypeIds', []),
5286
5338
  customWhere: root => getQueryParameter$2(root, 'customWhere', []),
5287
5339
  dynamicOrderBy: root => getQueryParameter$2(root, 'dynamicOrderBy', []),
5288
- env: ({
5289
- state,
5290
- facet,
5291
- context
5292
- }) => getCustomEnv(state, facet, context),
5293
5340
  excludeIds: ({
5294
5341
  action: {
5295
5342
  excludeIds
@@ -5320,9 +5367,7 @@ const queryParamsTemplate = {
5320
5367
  state
5321
5368
  }) => getPageIndex$2(state, '', action.context),
5322
5369
  internalPaging: root => getQueryParameter$2(root, 'internalPaging', false),
5323
- languages: ({
5324
- action
5325
- }) => action.defaultLang ? [action.defaultLang] : [],
5370
+ languages: root => getQueryParameter$2(root, 'languages', []),
5326
5371
  linkDepth: root => getQueryParameter$2(root, 'linkDepth', 0),
5327
5372
  loadMorePaging: root => getQueryParameter$2(root, 'loadMorePaging', false),
5328
5373
  omitDefaultSearchFields: root => getQueryParameter$2(root, 'omitDefaultSearchFields', []),
@@ -5359,7 +5404,7 @@ const queryParamsTemplate = {
5359
5404
  context
5360
5405
  }) => {
5361
5406
  var _getFacet;
5362
- return ((_getFacet = getFacet$1(state, facet, context, 'js')) === null || _getFacet === void 0 ? void 0 : _getFacet.projectId) || selectCurrentProject(state);
5407
+ return ((_getFacet = getFacet$1(state, facet, context, 'js')) === null || _getFacet === void 0 ? void 0 : _getFacet.projectId) || selectors$2.selectCurrentProject(state);
5363
5408
  },
5364
5409
  searchTerm: root => root.context !== Context.minilist || getQueryParameter$2(root, 'useSearchTerm', false) ? getSearchTerm$2(root.state) : '',
5365
5410
  selectedFilters: ({
@@ -5369,7 +5414,7 @@ const queryParamsTemplate = {
5369
5414
  }) => Object.fromEntries(Object.entries(getSelectedFilters(state, facet, context, 'js')).map(([key, f]) => [key, f === null || f === void 0 ? void 0 : f.join(',')])),
5370
5415
  versionStatus: root => {
5371
5416
  const versionStatusOverride = getQueryParameter$2(root, 'versionStatus');
5372
- return versionStatusOverride || selectVersionStatus(root.state);
5417
+ return versionStatusOverride || version.selectVersionStatus(root.state);
5373
5418
  },
5374
5419
  weightedSearchFields: root => {
5375
5420
  const wsf = getQueryParameter$2(root, 'weightedSearchFields', []);
@@ -5412,23 +5457,30 @@ const generateQueryParams = (action, state) => {
5412
5457
  const runSearch = (action, state, queryParams) => {
5413
5458
  const {
5414
5459
  context,
5415
- defaultLang,
5460
+ // defaultLang,
5416
5461
  facet,
5417
5462
  ogState = state,
5418
5463
  preload,
5419
- ssr
5464
+ isSSR
5420
5465
  } = action;
5421
5466
  let willRun = false;
5422
- const facetIsLoaded = defaultLang ? false : getIsLoaded(state, context, facet);
5467
+
5468
+ // const facetIsLoaded = defaultLang
5469
+ // ? false
5470
+ // : getIsLoaded(state, context, facet);
5471
+ const facetIsLoaded = getIsLoaded(state, context, facet);
5423
5472
  const stateParams = {
5424
5473
  ...getQueryParams(ogState, facet, context)
5425
5474
  };
5426
5475
  stateParams.pageIndex = getPageIndex$2(ogState, facet, context);
5427
5476
  stateParams.searchTerm = getSearchTerm$2(ogState);
5428
5477
  stateParams.pageSize = getPageSize(ogState, facet, context);
5429
- if (context === Context.facets && ssr ||
5478
+ if (isSSR ||
5479
+ // (context === Context.facets && isSSR) ||
5430
5480
  // context === Context.minilist ||
5431
- preload || !facetIsLoaded || filterParamsChanged(action) || defaultLang) {
5481
+ preload || !facetIsLoaded || filterParamsChanged(action) ||
5482
+ // || defaultLang
5483
+ languageChanged(action)) {
5432
5484
  willRun = true;
5433
5485
  } else {
5434
5486
  // Don't execute the search if the inbound query params
@@ -5447,6 +5499,20 @@ const runSearch = (action, state, queryParams) => {
5447
5499
  return willRun;
5448
5500
  };
5449
5501
 
5502
+ /**
5503
+ * Patch mutates original params argument to decode certain
5504
+ * url encoded params which can creep into urls and cause a
5505
+ * flash of different content when hydrating from SSR
5506
+ * @param params SearchParams
5507
+ * @returns SearchParams
5508
+ */
5509
+ const sanitiseParams = params => {
5510
+ if (params && typeof params === 'object') for (const param of Object.keys(params)) {
5511
+ if (typeof params[param] === 'string') params[param] = params[param].replaceAll('%2C', ',');
5512
+ }
5513
+ return params;
5514
+ };
5515
+
5450
5516
  /**
5451
5517
  * This will tell us if filter parameters have been
5452
5518
  * changed by some external event such as a route change
@@ -5463,12 +5529,17 @@ const filterParamsChanged = (action, state) => {
5463
5529
  const selectedFilters = getSelectedFilters(ogState, facet, context, 'js');
5464
5530
  const paramsChanged = Object.entries(selectedFilters).map(([filterKey, selectedValues]) => {
5465
5531
  const inboundValues = params && params[filterKey] && params[filterKey].split(',') || [];
5466
- if (!areArraysEqualSets(selectedValues, inboundValues)) return true;
5532
+ if (!util.areArraysEqualSets(selectedValues, inboundValues)) return true;
5467
5533
  });
5468
5534
  return paramsChanged.filter(f => f === true).length > 0;
5469
5535
  };
5470
-
5471
- /* eslint-disable no-console */
5536
+ const languageChanged = action => {
5537
+ const stateLanguages = getQueryParameter$2({
5538
+ ...action,
5539
+ state: action.ogState
5540
+ }, 'languages', []);
5541
+ return !util.areArraysEqualSets(action.languages || [], stateLanguages);
5542
+ };
5472
5543
  const debugExecuteSearch = (action, state) => {
5473
5544
  const [queryParams, runSearch] = generateQueryParams(action, state);
5474
5545
  console.log('runSearch', runSearch, 'action', action, 'filterParamsChanged', filterParamsChanged(action, state), 'getIsLoaded(state, context, facet)', getIsLoaded(state, action.context, action.facet));
@@ -5549,40 +5620,97 @@ function* setRouteFilters(action) {
5549
5620
  const {
5550
5621
  mappers,
5551
5622
  params,
5552
- listingType,
5553
- defaultLang,
5554
- debug
5623
+ composition,
5624
+ debug,
5625
+ ssr
5626
+ } = action;
5627
+ let {
5628
+ defaultLang
5555
5629
  } = action;
5556
- const context = listingType ? Context.listings : Context.facets;
5557
5630
  const state = toJS(yield effects.select());
5558
- const ssr = getIsSsr(state);
5631
+ const isSSR = getIsSsr(state);
5632
+ sanitiseParams(params);
5559
5633
 
5560
5634
  // Get current facet from params or state
5561
- let currentFacet = params && params.facet || listingType;
5635
+ const facet = (params === null || params === void 0 ? void 0 : params.facet) || action.facet;
5636
+ const listingType = (params === null || params === void 0 ? void 0 : params.listingType) || action.listingType;
5637
+
5638
+ // Determine facets or listings context
5639
+ let context = listingType ? Context.listings : Context.facets;
5640
+ let currentFacet = listingType || facet;
5641
+
5642
+ // Instead of just taking the facet/listing from params,
5643
+ // we need to check all aliases to determine the correct facet/listing
5644
+ const currentLanguage = yield effects.select(selectors$1.selectCurrentLanguage);
5645
+ if (currentFacet) {
5646
+ const currentLocalised = yield effects.select(getCurrentFromLocalised, currentFacet, currentLanguage, context);
5647
+ if (currentLocalised) {
5648
+ currentFacet = currentLocalised.facet;
5649
+ defaultLang = currentLocalised.language;
5650
+ }
5651
+ }
5562
5652
 
5563
- // If Listing use listing type (ignore params.facet)
5564
- if (context === Context.listings) {
5565
- currentFacet = listingType;
5653
+ // If composition is set, and no facet/listingType in params,
5654
+ // pick the first facet/listing from the composition
5655
+ if (composition) {
5656
+ const compositions = getSearchCompositions(state);
5657
+ const compositionConfig = compositions[composition];
5658
+ if (compositionConfig) {
5659
+ if ('facets' in compositionConfig) {
5660
+ if (!facet) {
5661
+ var _compositionConfig$fa;
5662
+ const firstFacetKey = (_compositionConfig$fa = compositionConfig.facets) === null || _compositionConfig$fa === void 0 ? void 0 : _compositionConfig$fa[0];
5663
+ context = Context.facets;
5664
+ currentFacet = firstFacetKey;
5665
+ }
5666
+ } else if ('listings' in compositionConfig) {
5667
+ if (!listingType) {
5668
+ var _compositionConfig$li;
5669
+ const firstListingKey = (_compositionConfig$li = compositionConfig.listings) === null || _compositionConfig$li === void 0 ? void 0 : _compositionConfig$li[0];
5670
+ context = Context.listings;
5671
+ currentFacet = firstListingKey;
5672
+ }
5673
+ }
5674
+ }
5566
5675
  }
5567
5676
 
5568
- // Patch any url encoded params which can cause a flash in SSR
5569
- if (params) for (const param of Object.keys(params)) {
5570
- params[param] = params[param].replaceAll('%2C', ',');
5677
+ // If Listing use listing type (ignore params.facet)
5678
+ if (context === Context.listings && listingType) {
5679
+ currentFacet = listingType;
5571
5680
  }
5572
5681
 
5573
5682
  // Pick the default facet from initialState
5574
5683
  if (!currentFacet) {
5575
- var _Object$keys;
5684
+ var _tabs$, _Object$keys;
5576
5685
  const tabs = getSearchTabs(state, 'js');
5577
- currentFacet = (tabs === null || tabs === void 0 ? void 0 : tabs[0].defaultFacet) || ((_Object$keys = Object.keys(getFacets(state, 'js'))) === null || _Object$keys === void 0 ? void 0 : _Object$keys[0]) || '';
5686
+ currentFacet = (tabs === null || tabs === void 0 || (_tabs$ = tabs[0]) === null || _tabs$ === void 0 ? void 0 : _tabs$.defaultFacet) || ((_Object$keys = Object.keys(getFacets(state, 'js'))) === null || _Object$keys === void 0 ? void 0 : _Object$keys[0]) || '';
5687
+ }
5688
+
5689
+ // Ensure we have a language set
5690
+ if (!defaultLang) defaultLang = currentLanguage;
5691
+
5692
+ // When we have a currentFacet, check the defaultLang
5693
+ // and translate any filter params from the localised aliases
5694
+ // to the actual filter keys
5695
+ if (currentFacet && defaultLang) {
5696
+ for (const paramKey of Object.keys(params || {})) {
5697
+ const filterKey = yield effects.select(getFilterKeyFromLocalised, paramKey, defaultLang, currentFacet, context);
5698
+ if (filterKey && filterKey !== paramKey) {
5699
+ params[filterKey] = params[paramKey];
5700
+ delete params[paramKey];
5701
+ }
5702
+ }
5578
5703
  }
5579
5704
  const nextAction = {
5580
5705
  type: SET_ROUTE_FILTERS,
5581
5706
  context,
5707
+ composition,
5582
5708
  facet: currentFacet,
5583
5709
  mappers,
5584
5710
  params,
5585
5711
  defaultLang,
5712
+ languages: defaultLang ? [defaultLang] : [],
5713
+ isSSR,
5586
5714
  ssr,
5587
5715
  debug
5588
5716
  };
@@ -5614,7 +5742,7 @@ function* doSearch(action) {
5614
5742
  const nextAction = {
5615
5743
  ...action,
5616
5744
  type: SET_SEARCH_FILTERS,
5617
- ssr: getIsSsr(state),
5745
+ isSSR: getIsSsr(state),
5618
5746
  facet: action.facet || ((_action$params = action.params) === null || _action$params === void 0 ? void 0 : _action$params.facet)
5619
5747
  };
5620
5748
  if (nextAction.facet && (action.config || Object.keys(getFacet$1(state, nextAction.facet, action.context, 'js')).length > 0)) {
@@ -5634,7 +5762,9 @@ function* loadFilters(action) {
5634
5762
  const {
5635
5763
  facet: facetKey,
5636
5764
  context,
5637
- mappers = {}
5765
+ mappers = {},
5766
+ languages,
5767
+ ssr
5638
5768
  } = action;
5639
5769
  const filtersToLoad = yield effects.select(getFiltersToLoad, facetKey, context, 'js');
5640
5770
  if (filtersToLoad.length > 0) {
@@ -5642,7 +5772,8 @@ function* loadFilters(action) {
5642
5772
  type: LOAD_FILTERS,
5643
5773
  filtersToLoad,
5644
5774
  facetKey,
5645
- context
5775
+ context,
5776
+ languages
5646
5777
  });
5647
5778
  const selectedKeys = yield effects.select(getSelectedFilters, facetKey, context, 'js');
5648
5779
  const facet = yield effects.select(getFacet$1, facetKey, context, 'js');
@@ -5654,9 +5785,11 @@ function* loadFilters(action) {
5654
5785
  filterKey,
5655
5786
  filter: filters[filterKey],
5656
5787
  projectId,
5788
+ languages,
5657
5789
  selectedKeys: selectedKeys[filterKey],
5658
5790
  context,
5659
- mapper: 'filterItems' in mappers && mappers.filterItems || mapEntriesToFilterItems
5791
+ mapper: 'filterItems' in mappers && mappers.filterItems || mapEntriesToFilterItems,
5792
+ ssr
5660
5793
  });
5661
5794
  });
5662
5795
  if (filtersToLoadSagas) yield effects.all(filtersToLoadSagas);
@@ -5664,17 +5797,26 @@ function* loadFilters(action) {
5664
5797
  }
5665
5798
  function* loadFilter(action) {
5666
5799
  const {
5800
+ context,
5667
5801
  facetKey,
5668
- filterKey,
5669
5802
  filter,
5803
+ filterKey,
5804
+ languages,
5805
+ mapper,
5670
5806
  projectId,
5671
5807
  selectedKeys,
5672
- context,
5673
- mapper
5808
+ // get api instance from SSR context that is connected to the current request in SSR,
5809
+ // fall back to the imported cachedSearch api that is not connected to the current SSR context
5810
+ ssr: {
5811
+ api
5812
+ } = {
5813
+ api: ContensisDeliveryApi.cachedSearch
5814
+ }
5674
5815
  } = action;
5675
5816
  const {
5676
5817
  contentTypeId,
5677
5818
  customWhere,
5819
+ pageSize,
5678
5820
  path
5679
5821
  } = filter;
5680
5822
  const createStateFrom = {
@@ -5682,6 +5824,7 @@ function* loadFilter(action) {
5682
5824
  context,
5683
5825
  error: undefined,
5684
5826
  facetKey,
5827
+ filter,
5685
5828
  filterKey,
5686
5829
  payload: {},
5687
5830
  selectedKeys,
@@ -5689,16 +5832,16 @@ function* loadFilter(action) {
5689
5832
  };
5690
5833
  try {
5691
5834
  if (contentTypeId) {
5692
- const versionStatus = yield effects.select(selectVersionStatus);
5693
- const query = filterQuery(Array.isArray(contentTypeId) ? contentTypeId : [contentTypeId], versionStatus, customWhere);
5694
- const payload = yield cachedSearch.search(query, 0, projectId);
5835
+ const versionStatus = yield effects.select(version.selectVersionStatus);
5836
+ const query = filterQuery(Array.isArray(contentTypeId) ? contentTypeId : [contentTypeId], languages, versionStatus, customWhere, pageSize);
5837
+ const payload = yield api.search(query, 0, projectId);
5695
5838
  if (!payload) throw new Error('No payload returned by search');
5696
5839
  if (payload.type === 'error') throw payload;
5697
5840
  createStateFrom.payload = payload;
5698
5841
  }
5699
5842
  if (path) {
5700
- const payload = yield cachedSearch.getTaxonomyNodeByPath(path, projectId);
5701
- if (!payload) throw new Error(`No payload returned for taxonomy path: '${path}'`);
5843
+ const payload = yield cachedTaxonomyLookup.getTaxonomyNodeByPath(path, projectId);
5844
+ if (!payload) throw new Error(`Nothing returned for taxonomy: '${path}'`);
5702
5845
  if (payload.type === 'error') throw payload;
5703
5846
  createStateFrom.payload = payload;
5704
5847
  }
@@ -5741,7 +5884,7 @@ function* ensureSearch(action) {
5741
5884
  });
5742
5885
  }
5743
5886
  } catch (error) {
5744
- log__namespace.error(...['Error running search saga:', error, error.stack]);
5887
+ log__namespace.error('Error running ensureSearch:', error, error.stack);
5745
5888
  }
5746
5889
  }
5747
5890
  function* executeSearch(action) {
@@ -5749,7 +5892,8 @@ function* executeSearch(action) {
5749
5892
  context,
5750
5893
  facet,
5751
5894
  queryParams,
5752
- mappers
5895
+ mappers,
5896
+ ssr
5753
5897
  } = action;
5754
5898
  try {
5755
5899
  const state = yield effects.select();
@@ -5759,19 +5903,19 @@ function* executeSearch(action) {
5759
5903
  const customApi = getCustomApi(state, facet, context, 'js');
5760
5904
  if (customApi) {
5761
5905
  const apiParams = typeof mappers === 'object' && typeof mappers.customApi === 'function' && mappers.customApi(queryParams) || mapQueryParamsToCustomApi(queryParams);
5762
- result.payload = yield callCustomApi(customApi, apiParams);
5906
+ result.payload = yield util.callCustomApi(customApi, apiParams, ssr);
5763
5907
  result.duration = 1;
5764
5908
  } else {
5765
5909
  if (queryParams.featuredResults) {
5766
5910
  featuredQuery = searchQuery(queryParams, true);
5767
- featuredResult = yield timedSearch(featuredQuery, queryParams.linkDepth, queryParams.projectId, queryParams.env);
5768
- queryParams.excludeIds = getItemsFromResult(featuredResult).map(fi => {
5911
+ featuredResult = yield util.timedSearch(featuredQuery, queryParams.linkDepth, queryParams.projectId, ssr);
5912
+ queryParams.excludeIds = util.getItemsFromResult(featuredResult).map(fi => {
5769
5913
  var _fi$sys;
5770
5914
  return fi === null || fi === void 0 || (_fi$sys = fi.sys) === null || _fi$sys === void 0 ? void 0 : _fi$sys.id;
5771
5915
  }).filter(fi => typeof fi === 'string');
5772
5916
  }
5773
5917
  const query = searchQuery(queryParams);
5774
- result = yield timedSearch(query, queryParams.linkDepth, queryParams.projectId, queryParams.env);
5918
+ result = yield util.timedSearch(query, queryParams.linkDepth, queryParams.projectId, ssr);
5775
5919
  }
5776
5920
  const createStateFrom = {
5777
5921
  action,
@@ -5784,7 +5928,7 @@ function* executeSearch(action) {
5784
5928
  const nextAction = mapJson__default.default(createStateFrom, facetTemplate);
5785
5929
  yield effects.put(nextAction);
5786
5930
  } catch (error) {
5787
- log__namespace.error(...['Error running search saga:', error, error.stack]);
5931
+ log__namespace.error('Error running executeSearch:', error, error.stack);
5788
5932
  }
5789
5933
  }
5790
5934
  function* preloadOtherFacets(action) {
@@ -5795,9 +5939,10 @@ function* preloadOtherFacets(action) {
5795
5939
  debug
5796
5940
  } = action;
5797
5941
  const state = yield effects.select();
5798
- const currentFacet = getCurrentFacet(state);
5799
- if (!preload && facet === currentFacet && context !== Context.listings) {
5800
- const allFacets = getFacets(state, 'js');
5942
+ const currentFacet = getCurrent$2(state, context);
5943
+ const currentComposition = getCurrentComposition(state);
5944
+ if (!preload && facet === currentFacet && (context !== Context.listings || currentComposition)) {
5945
+ const allFacets = currentComposition ? getCompositionFacets(state, currentComposition) : getFacets(state, 'js');
5801
5946
  const otherFacets = Object.keys(allFacets).filter(f => f !== currentFacet);
5802
5947
  yield effects.all(otherFacets.map((preloadFacet = '') => {
5803
5948
  const preloadAction = {
@@ -5838,9 +5983,13 @@ function* updateCurrentTab(action) {
5838
5983
  }
5839
5984
  function* clearFilters(action) {
5840
5985
  const {
5986
+ clear,
5841
5987
  mappers
5842
5988
  } = action;
5843
- const uri = yield buildUri({}, mappers);
5989
+ const term = clear !== null && clear !== void 0 && clear.term ? '' : undefined;
5990
+ const uri = yield buildUri({
5991
+ term
5992
+ }, mappers);
5844
5993
  yield effects.put(navigate(uri));
5845
5994
  }
5846
5995
  function* updateCurrentFacet(action) {
@@ -5982,6 +6131,7 @@ exports.getPaging = getPaging;
5982
6131
  exports.getQueryParameter = getQueryParameter$2;
5983
6132
  exports.getRenderableFilters = getRenderableFilters$2;
5984
6133
  exports.getResults = getResults;
6134
+ exports.getResultsInfo = getResultsInfo;
5985
6135
  exports.getSearchTerm = getSearchTerm$2;
5986
6136
  exports.getSearchTotalCount = getSearchTotalCount$1;
5987
6137
  exports.getSelectedFilters = getSelectedFilters;
@@ -5990,13 +6140,11 @@ exports.getTabsAndFacets = getTabsAndFacets$1;
5990
6140
  exports.getTotalCount = getTotalCount$1;
5991
6141
  exports.orderByExpression = orderByExpression;
5992
6142
  exports.queries = queries;
5993
- exports.routeParams = routeParams;
5994
6143
  exports.searchSagas = searchSagas;
5995
6144
  exports.selectListing = selectListing;
5996
6145
  exports.selectors = selectors;
5997
6146
  exports.setRouteFilters = setRouteFilters;
5998
6147
  exports.termExpressions = termExpressions;
5999
- exports.toArray = toArray;
6000
6148
  exports.triggerListingSsr = triggerListingSsr;
6001
6149
  exports.triggerMinilistSsr = triggerMinilistSsr;
6002
6150
  exports.triggerSearch = triggerSearch;
@@ -6012,4 +6160,4 @@ exports.updateSortOrder = updateSortOrder$1;
6012
6160
  exports.useFacets = useFacets;
6013
6161
  exports.useListing = useListing;
6014
6162
  exports.withMappers = withMappers;
6015
- //# sourceMappingURL=sagas-BVX4Ps1e.js.map
6163
+ //# sourceMappingURL=sagas-BCy9u6zA.js.map