@shopgate/engage 7.28.0 → 7.29.0-alpha.10

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 (167) hide show
  1. package/category/components/CategoryImage/index.js +1 -1
  2. package/category/components/CategoryList/index.js +7 -3
  3. package/category/components/CategoryList/style.js +1 -1
  4. package/components/ResponsiveContainer/breakpoints.js +2 -2
  5. package/components/SheetList/components/Item/index.js +7 -7
  6. package/components/Typography/Typography.d.ts +132 -0
  7. package/components/Typography/Typography.js +11 -0
  8. package/components/Typography/index.js +1 -0
  9. package/components/View/components/Content/index.js +4 -1
  10. package/components/View/components/Content/style.js +1 -1
  11. package/components/View/context.js +1 -1
  12. package/components/index.js +2 -2
  13. package/core/constants/index.js +8 -2
  14. package/core/constants/merchantSettings.js +1 -1
  15. package/core/constants/shopSettings.js +1 -1
  16. package/core/contexts/ThemeResourcesContext.d.ts +10 -1
  17. package/core/contexts/ThemeResourcesContext.js +1 -1
  18. package/core/helpers/scrollContainer.js +2 -2
  19. package/core/hocs/withThemeResources.js +4 -1
  20. package/core/hooks/events/index.js +1 -1
  21. package/core/hooks/events/useLongPress.js +1 -1
  22. package/core/hooks/events/usePressHandler.js +38 -0
  23. package/core/hooks/useThemeResources.js +6 -5
  24. package/core/providers/ThemeResourcesProvider.js +9 -5
  25. package/core/reducers/merchantSettings.js +1 -1
  26. package/core/reducers/shopSettings.js +1 -1
  27. package/core/selectors/index.js +1 -1
  28. package/core/selectors/merchantSettings.js +5 -2
  29. package/core/selectors/shopSettings.js +5 -2
  30. package/development/action-creators/settings.js +6 -2
  31. package/development/components/ClientInformation/ClientInformation.js +5 -0
  32. package/development/components/ClientInformation/actions.js +4 -0
  33. package/development/components/ClientInformation/index.js +1 -0
  34. package/development/components/DevelopmentSettings/DevelopmentSettings.js +9 -0
  35. package/development/components/DevelopmentSettings/index.js +1 -0
  36. package/development/components/DevelopmentTools/hooks.js +2 -2
  37. package/development/components/index.js +1 -1
  38. package/development/constants/actionTypes.js +1 -1
  39. package/development/reducers/settings.js +3 -3
  40. package/development/selectors/settings.js +4 -1
  41. package/locations/subscriptions.js +2 -2
  42. package/package.json +9 -7
  43. package/page/action-creators/index.js +22 -0
  44. package/page/components/ResponsiveWidgetImage/ResponsiveWidgetImage.js +7 -0
  45. package/page/components/ResponsiveWidgetImage/index.js +1 -0
  46. package/page/components/WidgetHeadline/WidgetHeadline.js +7 -0
  47. package/page/components/WidgetHeadline/index.js +1 -0
  48. package/page/components/WidgetRichText/WidgetRichText.js +6 -0
  49. package/page/components/WidgetRichText/index.js +1 -0
  50. package/page/components/Widgets/Overlay.js +51 -0
  51. package/page/components/Widgets/Tooltip.js +22 -0
  52. package/page/components/Widgets/Widget.js +17 -0
  53. package/page/components/Widgets/WidgetContext.d.ts +42 -0
  54. package/page/components/Widgets/WidgetContext.js +9 -0
  55. package/page/components/Widgets/WidgetProvider.js +8 -0
  56. package/page/components/Widgets/Widgets.js +11 -0
  57. package/page/components/Widgets/WidgetsPreviewContext.js +9 -0
  58. package/page/components/Widgets/WidgetsPreviewProvider.js +8 -0
  59. package/page/components/Widgets/constants.js +4 -0
  60. package/page/components/Widgets/events.js +23 -0
  61. package/page/components/Widgets/helpers.js +23 -0
  62. package/page/components/Widgets/hooks.js +69 -0
  63. package/page/components/Widgets/index.js +1 -0
  64. package/page/components/Widgets/types.d.ts +132 -0
  65. package/page/components/index.js +1 -1
  66. package/page/constants/actionTypes.js +1 -0
  67. package/page/constants/index.js +5 -1
  68. package/page/helpers/index.d.ts +55 -0
  69. package/page/helpers/index.js +17 -0
  70. package/page/hooks/index.d.ts +60 -0
  71. package/page/hooks/index.js +37 -0
  72. package/page/index.js +1 -2
  73. package/page/reducers/index.js +15 -0
  74. package/page/selectors/index.js +56 -2
  75. package/page/subscriptions/index.js +4 -0
  76. package/page/widgets/CategoryList/CategoryList.js +4 -0
  77. package/page/widgets/CategoryList/hooks.js +16 -0
  78. package/page/widgets/CategoryList/index.js +1 -0
  79. package/page/widgets/CategoryList/selectors.js +8 -0
  80. package/page/widgets/HTML/HTML.js +5 -0
  81. package/page/widgets/HTML/hooks.js +12 -0
  82. package/page/widgets/HTML/index.js +1 -0
  83. package/page/widgets/Headline/Headline.js +4 -0
  84. package/page/widgets/Headline/index.js +1 -0
  85. package/page/widgets/HeroBanner/HeroBanner.js +3 -0
  86. package/page/widgets/HeroBanner/hooks.js +14 -0
  87. package/page/widgets/HeroBanner/index.js +1 -0
  88. package/page/widgets/Image/Image.js +4 -0
  89. package/page/widgets/Image/hooks.js +19 -0
  90. package/page/widgets/Image/index.js +1 -0
  91. package/page/widgets/ImageRow/ImageRow.js +4 -0
  92. package/page/widgets/ImageRow/hooks.js +15 -0
  93. package/page/widgets/ImageRow/index.js +1 -0
  94. package/page/widgets/ImageSlider/ImageSlider.js +4 -0
  95. package/page/widgets/ImageSlider/hooks.js +33 -0
  96. package/page/widgets/ImageSlider/index.js +1 -0
  97. package/page/widgets/Placeholder/Placeholder.js +5 -0
  98. package/page/widgets/Placeholder/hooks.js +12 -0
  99. package/page/widgets/Placeholder/index.js +1 -0
  100. package/page/widgets/ProductList/ProductList.js +5 -0
  101. package/page/widgets/ProductList/hooks.js +21 -0
  102. package/page/widgets/ProductList/index.js +1 -0
  103. package/page/widgets/ProductSlider/ProductSlider.js +5 -0
  104. package/page/widgets/ProductSlider/hooks.js +24 -0
  105. package/page/widgets/ProductSlider/index.js +1 -0
  106. package/page/widgets/RichText/RichText.js +3 -0
  107. package/page/widgets/RichText/hooks.js +10 -0
  108. package/page/widgets/RichText/index.js +1 -0
  109. package/page/widgets/index.js +1 -0
  110. package/page/widgets/widgets.json +35 -0
  111. package/product/components/ProductCard/index.js +1 -1
  112. package/product/components/ProductGrid/components/Item/components/ItemDetails/index.js +8 -0
  113. package/product/components/ProductGrid/components/Item/components/ItemDetails/spec.js +1 -0
  114. package/product/components/ProductGrid/components/Item/components/ItemDiscount/index.js +5 -0
  115. package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/index.js +5 -0
  116. package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/spec.js +1 -0
  117. package/product/components/ProductGrid/components/Item/components/ItemImage/index.js +5 -0
  118. package/product/components/ProductGrid/components/Item/components/ItemImage/spec.js +1 -0
  119. package/product/components/ProductGrid/components/Item/components/ItemName/index.js +5 -0
  120. package/product/components/ProductGrid/components/Item/components/ItemName/spec.js +1 -0
  121. package/product/components/ProductGrid/components/Item/components/ItemPrice/index.js +5 -0
  122. package/product/components/ProductGrid/components/Item/components/ItemPrice/spec.js +1 -0
  123. package/product/components/ProductGrid/components/Item/index.js +7 -0
  124. package/product/components/ProductGrid/components/Iterator/index.js +5 -0
  125. package/product/components/ProductGrid/components/Layout/index.js +5 -0
  126. package/product/components/ProductGrid/index.js +22 -0
  127. package/product/components/ProductGrid/spec.js +1 -0
  128. package/product/components/ProductGridPrice/index.js +1 -1
  129. package/product/components/ProductSlider/index.js +4 -4
  130. package/product/components/index.js +1 -1
  131. package/styles/helpers/color.js +23 -0
  132. package/styles/helpers/index.js +1 -1
  133. package/styles/helpers/setPageBackgroundColor.js +2 -2
  134. package/styles/index.d.ts +17 -0
  135. package/styles/index.js +1 -1
  136. package/styles/theme/createTheme/createBreakpoints.d.ts +114 -0
  137. package/styles/theme/createTheme/createBreakpoints.js +41 -0
  138. package/styles/theme/createTheme/createPalette.d.ts +36 -0
  139. package/styles/theme/createTheme/createPalette.js +4 -0
  140. package/styles/theme/createTheme/createSpacing.d.ts +23 -0
  141. package/styles/theme/createTheme/createSpacing.js +14 -0
  142. package/styles/theme/createTheme/createTypography.d.ts +55 -0
  143. package/styles/theme/createTheme/createTypography.js +23 -0
  144. package/styles/theme/createTheme/index.d.ts +41 -0
  145. package/styles/theme/createTheme/index.js +5 -0
  146. package/styles/theme/createTheme/transitions.d.ts +100 -0
  147. package/styles/theme/createTheme/transitions.js +26 -0
  148. package/styles/theme/createTheme/zIndex.d.ts +12 -0
  149. package/styles/theme/createTheme/zIndex.js +3 -0
  150. package/styles/theme/hooks/index.d.ts +4 -0
  151. package/styles/theme/hooks/index.js +1 -0
  152. package/styles/theme/hooks/useActiveBreakpoint.d.ts +18 -0
  153. package/styles/theme/hooks/useActiveBreakpoint.js +4 -0
  154. package/styles/theme/hooks/useMediaQuery.d.ts +33 -0
  155. package/styles/theme/hooks/useMediaQuery.js +20 -0
  156. package/styles/theme/hooks/useResponsiveValue.d.ts +27 -0
  157. package/styles/theme/hooks/useResponsiveValue.js +4 -0
  158. package/styles/theme/hooks/useTheme.d.ts +8 -0
  159. package/styles/theme/hooks/useTheme.js +4 -0
  160. package/styles/theme/index.d.ts +8 -0
  161. package/styles/theme/index.js +1 -0
  162. package/styles/theme/providers/ActiveBreakpointProvider.d.ts +21 -0
  163. package/styles/theme/providers/ActiveBreakpointProvider.js +13 -0
  164. package/styles/theme/providers/ThemeProvider.d.ts +18 -0
  165. package/styles/theme/providers/ThemeProvider.js +7 -0
  166. package/styles/tss/index.js +3 -0
  167. package/tracking/selectors/cookieConsent.js +2 -2
@@ -0,0 +1,23 @@
1
+ import{PAGE_PREVIEW_PATTERN}from'@shopgate/engage/page/constants';/**
2
+ * Retrieves the scroll container for the current page. Depending on the PWA mode this can be
3
+ * a scrollable article element or the window.
4
+ * @returns {HTMLElement|null}
5
+ */export var getScrollContainer=function getScrollContainer(){return document.querySelector(".route__".concat(PAGE_PREVIEW_PATTERN.replace(/^\/+/,'')));};/**
6
+ * @typedef {Object} ScheduledParams
7
+ * @property {string} [from] The start date of the scheduling in ISO format.
8
+ * @property {string} [to] The end date of the scheduling in ISO format.
9
+ * @property {number} [timezoneOffset] The timezone offset in minutes. If not provided, the local
10
+ * timezone offset will be used.
11
+ */ /**
12
+ * @typedef {Object} ScheduledStatus
13
+ * @property {boolean} isScheduled Indicates if the widget is scheduled.
14
+ * @property {boolean} isActive Indicates if the widget is currently active within the
15
+ * scheduled time frame.
16
+ * @property {boolean} isExpired Indicates if the scheduled time frame has expired.
17
+ */ /**
18
+ * Retrieves the scheduling status of a widget based on the provided parameters.
19
+ * @param {ScheduledParams} [params] The parameters for the function.
20
+ * @returns {ScheduledStatus} An object containing the scheduling status.
21
+ */export function checkScheduled(){var _ref=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{},from=_ref.from,to=_ref.to,timezoneOffset=_ref.timezoneOffset;var now=new Date();// Convert current time to provided or local timezone
22
+ var localOffset=timezoneOffset!==null&&timezoneOffset!==void 0?timezoneOffset:-now.getTimezoneOffset();// in minutes
23
+ var offsetMs=localOffset*60*1000;var localNow=new Date(now.getTime()+offsetMs);var fromDate=from?new Date(from):null;var toDate=to?new Date(to):null;var isActive=(!fromDate||localNow>=new Date(fromDate.getTime()+offsetMs))&&(!toDate||localNow<=new Date(toDate.getTime()+offsetMs));var isExpired=!!toDate&&localNow>new Date(toDate.getTime()+offsetMs);var isScheduled=!!fromDate||!!toDate;return{isScheduled:isScheduled,isActive:isActive,isExpired:isExpired};}
@@ -0,0 +1,69 @@
1
+ import{useEffect,useCallback,useRef,useContext,useMemo}from'react';import{logger}from'@shopgate/engage/core/helpers';import{useDispatch}from'react-redux';import{useRoute}from'@shopgate/engage/core/hooks';import{receivePageConfigV2}from'@shopgate/engage/page/action-creators';import{PAGE_PREVIEW_SLUG}from'@shopgate/engage/page/constants';import{ALLOWED_PAGE_PREVIEW_ORIGINS,CONSIDER_CONTAINER_MARGINS_ON_SCROLL_DEFAULT}from"./constants";import{getScrollContainer}from"./helpers";import{WidgetsPreviewContext}from"./WidgetsPreviewContext";import{dispatchWidgetPreviewEvent,useWidgetPreviewEvent}from"./events";/**
2
+ * @typedef {Object} MessageData
3
+ * @property {string} type Identifier for the kind of message
4
+ * @property {any} [payload] Optional data payload for this message
5
+ */ /**
6
+ * @typedef {Object} IframeMessengerResult
7
+ * @property {function(MessageData, string=): void} sendToParent
8
+ * - Send data up to window.parent. If targetOrigin is omitted, uses the
9
+ * most recently seen origin (from an incoming message). If none seen yet,
10
+ * falls back to parentOrigins[0] or "*".
11
+ */ /**
12
+ * Hook for postMessage communication when your component is inside an iframe.
13
+ *
14
+ * Listens on window for "message" events from any origin in parentOrigins,
15
+ * and only calls onMessage(data, rawEvent) if both origin and source match.
16
+ *
17
+ * @param {function(MessageData, any): void} onMessage
18
+ * Callback invoked when a trusted message arrives. Receives data and the
19
+ * raw event (so you can inspect origin, source, etc.).
20
+ * @param {string[]} parentOrigins
21
+ * Array of allowed parent origin strings (e.g.
22
+ * ['https://a.example.com','https://b.example.com']).
23
+ * @returns {IframeMessengerResult}
24
+ * An object with a single method:
25
+ * • sendToParent(data, [targetOrigin]): void
26
+ * – Posts data up to window.parent. By default it uses the most recently
27
+ * seen origin (from an incoming message). If none, uses parentOrigins[0].
28
+ */function useIframeMessenger(onMessage,parentOrigins){// Keep a ref to the latest onMessage callback so the listener always has it.
29
+ var onMessageRef=useRef(onMessage);useEffect(function(){onMessageRef.current=onMessage;},[onMessage]);// Keep track of the last allowed origin we heard from
30
+ var lastOriginRef=useRef(null);/**
31
+ * Send a message up to the parent window.
32
+ * @param {MessageData} data - The data object to post.
33
+ * @param {string} [targetOrigin]
34
+ * Optional override for the origin to post to. Must be one of
35
+ * parentOrigins. If omitted, uses the last seen origin (lastOriginRef),
36
+ * or parentOrigins[0], or "*" if array is empty.
37
+ */var sendToParent=useCallback(function(data,targetOrigin){// Determine which origin to use: explicit, then last seen, then first, then "*".
38
+ var originToUse=typeof targetOrigin==='string'?targetOrigin:lastOriginRef.current||new URL(document.referrer).origin||parentOrigins[0]||'*';if(!originToUse){logger.warn('useIframeMessenger: no targetOrigin available. '+'Provide parentOrigins or pass targetOrigin.');return;}window.parent.postMessage(data,originToUse);},[parentOrigins]);// Attach / detach the "message" listener.
39
+ useEffect(function(){/**
40
+ * Handler for incoming postMessage events.
41
+ * @param {any} rawEvent – The original MessageEvent object.
42
+ */function handler(rawEvent){// Only proceed if the origin is in our whitelist.
43
+ if(!parentOrigins.includes(rawEvent.origin))return;// Ensure the message actually came from window.parent.
44
+ if(rawEvent.source!==window.parent)return;// Record this origin as most recently seen.
45
+ lastOriginRef.current=rawEvent.origin;// Forward the event.data and the raw event to the callback.
46
+ onMessageRef.current(rawEvent.data,rawEvent);}window.addEventListener('message',handler);return function(){window.removeEventListener('message',handler);};},[parentOrigins,sendToParent]);return{sendToParent:sendToParent};}/**
47
+ * Hook to handle communication with the parent window in a page preview iframe.
48
+ * @param {boolean} isActive Whether the preview communication is active.
49
+ */export var usePreviewIframeCommunication=function usePreviewIframeCommunication(){var isActive=arguments.length>0&&arguments[0]!==undefined?arguments[0]:false;var dispatch=useDispatch();var _useRoute=useRoute(),considerContainerMarginsOnScroll=_useRoute.query.considerContainerMarginsOnScroll;// Detect if container margins should be considered at scroll to widget.
50
+ var considerVerticalMargins=useMemo(function(){if(!considerContainerMarginsOnScroll){return CONSIDER_CONTAINER_MARGINS_ON_SCROLL_DEFAULT;}return considerContainerMarginsOnScroll==='true';},[considerContainerMarginsOnScroll]);var _useIframeMessenger=useIframeMessenger(function(data){var _data$payload;if(data.type==='receivePageConfig'){// Page preview config received from the parent window.
51
+ dispatch(receivePageConfigV2({type:'cms',slug:PAGE_PREVIEW_SLUG,data:data.payload}));}else if(data.type==='scrollToWidget'&&((_data$payload=data.payload)===null||_data$payload===void 0?void 0:_data$payload.widgetCode)){// Parent window requested to scroll to a specific widget.
52
+ var scrollContainer=getScrollContainer();var target=scrollContainer.querySelector("#widget-code-".concat(data.payload.widgetCode));if(scrollContainer&&target){var marginTop=0;if(considerVerticalMargins){var styles=window.getComputedStyle(target);marginTop=parseFloat(styles.marginTop);}var containerTop=scrollContainer.getBoundingClientRect().top;var targetTop=target.getBoundingClientRect().top;var scrollOffset=targetTop-containerTop+scrollContainer.scrollTop-marginTop;var maxScrollTop=scrollContainer.scrollHeight-scrollContainer.clientHeight;var actualScrollTop=Math.min(scrollOffset,maxScrollTop);// Register the target element as the active widget.
53
+ dispatchWidgetPreviewEvent('set-active-widget-id',data.payload.widgetCode);/**
54
+ * Callback to highlight the widget after scrolling.
55
+ */var highlightWidget=function highlightWidget(){dispatchWidgetPreviewEvent('highlight-widget',data.payload.widgetCode);};// Add listener to onScrollEnd if available, otherwise use scroll event.
56
+ if('onscrollend'in scrollContainer){/**
57
+ * Callback for the scrollend event.
58
+ */var onEnded=function onEnded(){scrollContainer.removeEventListener('scrollend',onEnded);highlightWidget();};scrollContainer.addEventListener('scrollend',onEnded,{once:true});scrollContainer.scrollTo({top:actualScrollTop,behavior:'smooth'});return;}// Fallback: listen for scroll events until scrollTop ≈ actualScrollTop
59
+ /**
60
+ * Callback for the scroll event.
61
+ */var onScroll=function onScroll(){// Allow a 1 px leeway for subpixel rendering
62
+ if(Math.abs(scrollContainer.scrollTop-actualScrollTop)<1){scrollContainer.removeEventListener('scroll',onScroll);highlightWidget();}};scrollContainer.addEventListener('scroll',onScroll);scrollContainer.scrollTo({top:actualScrollTop,behavior:'smooth'});}}},ALLOWED_PAGE_PREVIEW_ORIGINS),sendToParent=_useIframeMessenger.sendToParent;useWidgetPreviewEvent('widget-clicked',function(e){if(!isActive){return;}sendToParent({type:'widgetClicked',payload:{widgetCode:e.detail.widgetCode}});});};/**
63
+ * @typedef {import('./WidgetsPreviewContext.js').WidgetsPreviewContextType}
64
+ * WidgetsPreviewContextType
65
+ */ /**
66
+ * The useWidgetsPreview hook provides access to the context that is wrapped around the Widgets
67
+ * component when it's rendered in preview mode.
68
+ * @returns {WidgetsPreviewContextType} The widget context.
69
+ */export var useWidgetsPreview=function useWidgetsPreview(){return useContext(WidgetsPreviewContext);};
@@ -0,0 +1 @@
1
+ export{default}from"./Widgets";export{WidgetContext}from"./WidgetContext";
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Visibility settings for a widget.
3
+ */
4
+ export interface WidgetDefinitionVisibility {
5
+ /**
6
+ * Whether the widget is hidden.
7
+ */
8
+ isHidden: boolean;
9
+ /**
10
+ * Start date for scheduled widgets.
11
+ */
12
+ scheduleStartDate: string;
13
+ /**
14
+ * End date for scheduled widgets.
15
+ */
16
+ scheduleEndDate: string
17
+ }
18
+
19
+ /**
20
+ * Layout settings for a widget.
21
+ */
22
+ export interface WidgetDefinitionLayout {
23
+ /**
24
+ * Top margin for the widget.
25
+ */
26
+ marginTop: number;
27
+ /**
28
+ * Bottom margin for the widget.
29
+ */
30
+ marginBottom: number;
31
+ /**
32
+ * Left margin for the widget.
33
+ */
34
+ marginLeft: number;
35
+ /**
36
+ * Right margin for the widget.
37
+ */
38
+ marginRight: number;
39
+ }
40
+
41
+ /**
42
+ * Definition of a API widget
43
+ */
44
+ export interface WidgetDefinition {
45
+ /**
46
+ * Unique code for the widget.
47
+ */
48
+ code: string;
49
+ /**
50
+ * Name of the widget
51
+ */
52
+ widgetConfigDefinitionCode: string;
53
+ /**
54
+ * Individual configuration for the widget.
55
+ */
56
+ widgetConfig: Record<string, any>;
57
+ /**
58
+ * Whether the widget is a legacy custom widget provided by an extension that's configured
59
+ * via an HTML comment inside a HTML widget.
60
+ */
61
+ isCustomLegacyWidget?: boolean;
62
+ /**
63
+ * Visibility settings for the widget.
64
+ */
65
+ visibility: WidgetDefinitionVisibility;
66
+ /**
67
+ * Layout settings for the widget.
68
+ */
69
+ layout: WidgetDefinitionLayout;
70
+ /**
71
+ * Optional metadata for the widget (only available in preview mode)
72
+ */
73
+ meta?: {
74
+ /**
75
+ * Hidden state related data
76
+ */
77
+ hidden: {
78
+ /**
79
+ * Whether the widget is hidden.
80
+ */
81
+ isHidden: boolean;
82
+ /**
83
+ * Tooltip text for hidden related UI elements.
84
+ */
85
+ tooltip: string;
86
+ /**
87
+ * Label text for hidden related UI elements.
88
+ */
89
+ label: string;
90
+ };
91
+ /**
92
+ * Scheduled state related data
93
+ */
94
+ scheduled: {
95
+ /**
96
+ * Indicates if the widget is scheduled.
97
+ */
98
+ isScheduled: boolean;
99
+ /**
100
+ * Indicates that the widget schedule time frame is currently active.
101
+ */
102
+ isActive: boolean;
103
+ /**
104
+ * Indicates if the scheduled time frame has expired
105
+ */
106
+ isExpired: boolean;
107
+ /**
108
+ * Tooltip text for schedule related UI elements.
109
+ */
110
+ tooltip: string;
111
+ /**
112
+ * Label text for schedule related UI elements.
113
+ */
114
+ label: string;
115
+ };
116
+ }
117
+ }
118
+
119
+ export interface ScheduledStatus {
120
+ /**
121
+ * Indicates if the widget is scheduled.
122
+ */
123
+ isScheduled: boolean;
124
+ /**
125
+ * Indicates if the widget is currently hidden based on the scheduling
126
+ */
127
+ isHidden: boolean;
128
+ /**
129
+ * Indicates if the scheduled time frame has expired.
130
+ */
131
+ isExpired: boolean;
132
+ }
@@ -1 +1 @@
1
- export{default as NotFound}from"./NotFound";
1
+ export{default as NotFound}from"./NotFound";export{default as Widgets}from"./Widgets";export{default as ResponsiveWidgetImage}from"./ResponsiveWidgetImage";export{default as WidgetRichText}from"./WidgetRichText";
@@ -0,0 +1 @@
1
+ export var REQUEST_PAGE_CONFIG_V2='REQUEST_PAGE_CONFIG_V2';export var RECEIVE_PAGE_CONFIG_V2='RECEIVE_PAGE_CONFIG_V2';export var ERROR_PAGE_CONFIG_V2='ERROR_PAGE_CONFIG_V2';
@@ -1 +1,5 @@
1
- import{PAGE_PATH,PAGE_PATTERN}from'@shopgate/pwa-common/constants/RoutePaths';export*from'@shopgate/pwa-common/constants/PageIDs';export{PAGE_PATH,PAGE_PATTERN};export var IMPRINT_PATH="".concat(PAGE_PATH,"/imprint");export var PAYMENT_PATH="".concat(PAGE_PATH,"/payment");export var PRIVACY_PATH="".concat(PAGE_PATH,"/privacy");export var RETURN_POLICY_PATH="".concat(PAGE_PATH,"/return_policy");export var SHIPPING_PATH="".concat(PAGE_PATH,"/shipping");export var TERMS_PATH="".concat(PAGE_PATH,"/terms");
1
+ import{PAGE_PATH,PAGE_PATTERN}from'@shopgate/pwa-common/constants/RoutePaths';export*from'@shopgate/pwa-common/constants/PageIDs';export{PAGE_PATH,PAGE_PATTERN};export*from"./actionTypes";export var IMPRINT_PATH="".concat(PAGE_PATH,"/imprint");export var PAYMENT_PATH="".concat(PAGE_PATH,"/payment");export var PRIVACY_PATH="".concat(PAGE_PATH,"/privacy");export var RETURN_POLICY_PATH="".concat(PAGE_PATH,"/return_policy");export var SHIPPING_PATH="".concat(PAGE_PATH,"/shipping");export var TERMS_PATH="".concat(PAGE_PATH,"/terms");export var PAGE_PREVIEW_PATTERN='/shopgate-internal-page-preview';export var PAGE_PREVIEW_SLUG='page_preview';/**
2
+ * Checks if the app is currently in page preview mode.
3
+ */export var IS_PAGE_PREVIEW_ACTIVE=window.location.pathname.startsWith(PAGE_PREVIEW_PATTERN);/**
4
+ * One hour in milliseconds
5
+ */export var PAGE_STATE_LIFETIME=3600000;
@@ -0,0 +1,55 @@
1
+ export type ProductsWidgetInputConfig = {
2
+ /**
3
+ * Source type for the product list
4
+ */
5
+ productSelectorType: 'searchTerm' | 'brand' | 'category' | 'manualItemNumbers' | 'productSelector';
6
+ /**
7
+ * A search term to filter products by
8
+ */
9
+ productsSearchTerm: string;
10
+ /**
11
+ * A brand to filter products by
12
+ */
13
+ productsBrand: string;
14
+ /**
15
+ * A category to filter products by
16
+ */
17
+ productsCategory: string;
18
+ /**
19
+ * Array of product item numbers (selected via manual input)
20
+ */
21
+ productsManualItemNumbers: string[];
22
+ /**
23
+ * Array of product item numbers (selected via product selector)
24
+ */
25
+ productsSelectorItemNumbers: string[];
26
+ }
27
+
28
+ export type GetProductSearchParamsFromProductsInputConfigReturnValue = {
29
+ /**
30
+ * The type of product search to perform.
31
+ */
32
+ productsSearchType: 'searchTerm' | 'brand' | 'category' | 'productIds';
33
+ /**
34
+ * The value to use for the product search. Can be a string or an array of strings (for product IDs).
35
+ */
36
+ productsSearchValue: string | string[];
37
+ }
38
+
39
+ /**
40
+ * Helper to extract relevant search parameters from the widget configuration of the "Products"
41
+ * input.
42
+ *
43
+ * The return value can be used to e.g. parametrize the useWidgetProducts hook.
44
+ */
45
+ export declare function getProductSearchParamsFromProductsInputConfig(
46
+ products: ProductsWidgetInputConfig
47
+ ): GetProductSearchParamsFromProductsInputConfigReturnValue;
48
+
49
+ /**
50
+ * Helper to parse the image URL to return a high resolution version if required.
51
+ */
52
+ export declare function parseImageUrl(
53
+ url: string,
54
+ useHighRes?: boolean
55
+ ): string;
@@ -0,0 +1,17 @@
1
+ /* eslint-disable max-len */ /**
2
+ * @typedef {import('./').ProductsWidgetInputConfig} ProductsWidgetInputConfig
3
+ */ /**
4
+ * @typedef {import('./').GetProductSearchParamsFromProductsInputConfigReturnValue} GetProductSearchParamsFromProductsInputConfigReturnValue
5
+ */ /* eslint-enable max-len */ /**
6
+ * Helper to extract relevant search parameters from the widget configuration of the "Products"
7
+ * input.
8
+ * The return value can be used to e.g. parametrize the useWidgetProducts hook.
9
+ * @param {ProductsWidgetInputConfig} products Config object of the "Products" input.
10
+ * @returns {GetProductSearchParamsFromProductsInputConfigReturnValue}
11
+ */export var getProductSearchParamsFromProductsInputConfig=function getProductSearchParamsFromProductsInputConfig(){var products=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};var _ref=products||{},productSelectorType=_ref.productSelectorType,productsBrand=_ref.productsBrand,productsCategory=_ref.productsCategory,productsItemNumbers=_ref.productsItemNumbers,productsManualItemNumbers=_ref.productsManualItemNumbers,productsSelectorItemNumbers=_ref.productsSelectorItemNumbers,productsSearchTerm=_ref.productsSearchTerm;var productsSearchType=productSelectorType;/** @type {string|string[]} */var productsSearchValue='';switch(productSelectorType){case'brand':productsSearchValue=productsBrand;break;case'category':productsSearchValue=productsCategory;break;// Kept for backward compatibility - was replaces by 'manualItemNumbers' and 'productSelector'
12
+ case'itemNumbers':productsSearchValue=productsItemNumbers.split(',').map(function(item){return item.trim();});break;case'manualItemNumbers':productsSearchValue=productsManualItemNumbers;break;case'productSelector':productsSearchValue=productsSelectorItemNumbers;break;case'searchTerm':default:productsSearchValue=productsSearchTerm;}if(['itemNumbers','manualItemNumbers','productSelector'].includes(productSelectorType)){productsSearchType='productIds';}return{productsSearchType:productsSearchType,productsSearchValue:productsSearchValue};};/**
13
+ * Parses the image URL to return a high resolution version if required.
14
+ * @param {string} url The original image URL.
15
+ * @param {boolean} useHighRes Whether to return a high resolution version.
16
+ * @returns {string} The parsed image URL.
17
+ */export var parseImageUrl=function parseImageUrl(url,useHighRes){if(!url||!useHighRes){return url;}var match=url.match(/^(.*)\.([^./]+)$/);return!match?url:"".concat(match[1],"@2x.").concat(match[2]);};
@@ -0,0 +1,60 @@
1
+ import type { WidgetContextType } from '../components/Widgets/WidgetContext';
2
+
3
+ /**
4
+ * The useWidget hook provides access to the context that is wrapped around a widget.
5
+ * @returns The widget context.
6
+ */
7
+ export declare function useWidget<C = Record<string, any>>(): WidgetContextType<C>
8
+
9
+
10
+ export type UseWidgetProductsOptions = {
11
+ /**
12
+ * The search value to use for the product search
13
+ */
14
+ value: string;
15
+ /**
16
+ * The type of product search to perform.
17
+ */
18
+ type: 'searchTerm' | 'productIds' | 'brand' | 'category' | 'highlights';
19
+ /**
20
+ * The number of products to return per page.
21
+ * @default 32
22
+ */
23
+ limit?: number;
24
+ /**
25
+ * Sort order for the products
26
+ * @default 'relevance'
27
+ */
28
+ sort?: 'relevance' | 'priceAsc' | 'priceDesc' | 'nameAsc' | 'nameDesc';
29
+ };
30
+
31
+ export type UseWidgetProductsResult = {
32
+ /**
33
+ * Function to fetch the next page of products.
34
+ */
35
+ fetchNext: () => void;
36
+ /**
37
+ * Whether there are more products to fetch.
38
+ */
39
+ hasNext: boolean;
40
+ /**
41
+ * Whether the products are currently being fetched.
42
+ */
43
+ isFetching: boolean;
44
+ /**
45
+ * Number of products available in the current result set.
46
+ */
47
+ totalResultCount: number;
48
+ /**
49
+ * Array of product results.
50
+ */
51
+ results: Object[];
52
+ }
53
+
54
+ /**
55
+ * The useWidgetProducts hook provides an easy way to retrieve products based on a search term or
56
+ * other criteria.
57
+ */
58
+ export declare function useWidgetProducts(
59
+ options: UseWidgetProductsOptions
60
+ ): UseWidgetProductsResult;
@@ -0,0 +1,37 @@
1
+ import _regeneratorRuntime from"@babel/runtime/regenerator";function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg);var value=info.value;}catch(error){reject(error);return;}if(info.done){resolve(value);}else{Promise.resolve(value).then(_next,_throw);}}function _asyncToGenerator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value);}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err);}_next(undefined);});};}function _slicedToArray(arr,i){return _arrayWithHoles(arr)||_iterableToArrayLimit(arr,i)||_nonIterableRest();}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance");}function _iterableToArrayLimit(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally{try{if(!_n&&_i["return"]!=null)_i["return"]();}finally{if(_d)throw _e;}}return _arr;}function _arrayWithHoles(arr){if(Array.isArray(arr))return arr;}function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import{useContext,useMemo,useCallback,useEffect,useState}from'react';import{useSelector,useDispatch}from'react-redux';import{WidgetContext}from'@shopgate/engage/page/components/Widgets';import{showInventoryInLists}from'@shopgate/engage/locations/helpers';import{ITEMS_PER_LOAD}from'@shopgate/engage/core/constants';import{transformDisplayOptions}from'@shopgate/engage/core/helpers';import{fetchProductsByQuery}from'@shopgate/engage/product';import{makeGetWidgetProducts}from"../selectors";/**
2
+ * @typedef {import('../components/Widgets/WidgetContext').WidgetContextType WidgetContextType}
3
+ */ /**
4
+ * @typedef {import('./index').UseWidgetProductsOptions} UseWidgetProductsOptions
5
+ */ /**
6
+ * @typedef {import('./index').UseWidgetProductsResult} UseWidgetProductsResult
7
+ */ /**
8
+ * The useWidget hook provides access to the context that is wrapped around a widget.
9
+ * @returns {WidgetContextType} The widget context.
10
+ */export var useWidget=function useWidget(){return useContext(WidgetContext);};var REQUEST_TYPE_MAPPING={highlights:1,searchTerm:2,brand:3,productIds:4,category:5};/**
11
+ * Retrieves the products for the current widget.
12
+ * @param {UseWidgetProductsOptions} options Hook options
13
+ * @returns {UseWidgetProductsResult} The products and a function to fetch more products.
14
+ */export var useWidgetProducts=function useWidgetProducts(){var options=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{};var type=options.type,value=options.value,_options$limit=options.limit,limit=_options$limit===void 0?ITEMS_PER_LOAD:_options$limit,_options$sort=options.sort,sort=_options$sort===void 0?'relevance':_options$sort;var dispatch=useDispatch();var _useWidget=useWidget(),_useWidget$code=_useWidget.code,code=_useWidget$code===void 0?"".concat(type,"_").concat(value,"_").concat(limit,"_").concat(sort):_useWidget$code,isPreview=_useWidget.isPreview;// ###### Products selection ######
15
+ var showInventoryInProductLists=useSelector(showInventoryInLists);var selectorOptions=useMemo(function(){return _extends({sort:transformDisplayOptions(sort),value:value,useDefaultRequestForProductIds:true},showInventoryInProductLists&&{useDefaultRequestForProductIds:true});},[showInventoryInProductLists,sort,value]);var getWidgetProducts=useMemo(function(){return makeGetWidgetProducts(type,selectorOptions,code);},[code,selectorOptions,type]);var widgetProducts=useSelector(getWidgetProducts);// ###### Products request ######
16
+ // Outside the preview mode the offset and hasNext state are initialized based on previously
17
+ // fetched product data. That ensures that users see the same product list when they leave
18
+ // the page and come back later.
19
+ var _useState=useState(isPreview?0:widgetProducts.products.length),_useState2=_slicedToArray(_useState,2),offset=_useState2[0],setOffset=_useState2[1];var _useState3=useState(isPreview?true:widgetProducts.totalProductCount>widgetProducts.products.length),_useState4=_slicedToArray(_useState3,2),hasNext=_useState4[0],setHasNext=_useState4[1];var isFetching=widgetProducts.isFetching;var baseRequestOptions=useMemo(function(){return _extends({limit:limit,sort:transformDisplayOptions(sort),useDefaultRequestForProductIds:true},showInventoryInProductLists&&{useDefaultRequestForProductIds:true});},[limit,showInventoryInProductLists,sort]);/**
20
+ * Callback to dispatch the initial fetch request for products when the hook mounts,
21
+ * or when its parameters change.
22
+ */var fetchInitial=useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(){var _result$totalProductC;var initialOptions,result;return _regeneratorRuntime.wrap(function _callee$(_context){while(1)switch(_context.prev=_context.next){case 0:if(value){_context.next=3;break;}setHasNext(false);return _context.abrupt("return");case 3:// Initial request needs to start at offset 0
23
+ initialOptions=_extends({},baseRequestOptions,{offset:0});_context.next=6;return dispatch(fetchProductsByQuery(REQUEST_TYPE_MAPPING[type],value,initialOptions,code));case 6:result=_context.sent;// Re-initialize offset and hasNext based on the result
24
+ setOffset(limit);// When the result comes from a real pipeline request there will be "totalProductCount".
25
+ // When the result are cached products, it can also be "totalResultCount".
26
+ setHasNext(((_result$totalProductC=result.totalProductCount)!==null&&_result$totalProductC!==void 0?_result$totalProductC:result.totalResultCount)>limit);case 9:case"end":return _context.stop();}},_callee);})),[code,dispatch,type,value,limit,baseRequestOptions]);// Effect to trigger the initial fetch when the component mounts or the parameters change.
27
+ useEffect(function(){if(!isPreview&&offset===0||isPreview){fetchInitial();}// This effect should only run at first render or when the fetchInitial callback updates.
28
+ // fetchInitial will never be updated on a real "page" at runtime since its dependencies
29
+ // are static.
30
+ // In preview mode updates of fetchInitial are an essential part of the preview system.
31
+ // eslint-disable-next-line react-hooks/exhaustive-deps
32
+ },[fetchInitial]);/**
33
+ * Callback to fetch the next chunk of products when e.g. users interacted with a "Load More"
34
+ * button.
35
+ */var fetchNext=useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(){var _result$totalProductC2;var nextOptions,result;return _regeneratorRuntime.wrap(function _callee2$(_context2){while(1)switch(_context2.prev=_context2.next){case 0:if(!(!hasNext||isFetching||!value)){_context2.next=2;break;}return _context2.abrupt("return");case 2:nextOptions=_extends({},baseRequestOptions,{offset:offset});_context2.next=5;return dispatch(fetchProductsByQuery(REQUEST_TYPE_MAPPING[type],value,nextOptions,code));case 5:result=_context2.sent;setOffset(offset+limit);// When the result comes from a real pipeline request there will be "totalProductCount".
36
+ // When the result are cached products, it can also be "totalResultCount".
37
+ setHasNext(((_result$totalProductC2=result.totalProductCount)!==null&&_result$totalProductC2!==void 0?_result$totalProductC2:result.totalResultCount)>offset+limit);case 8:case"end":return _context2.stop();}},_callee2);})),[code,dispatch,hasNext,isFetching,value,offset,limit,baseRequestOptions,type]);return{fetchNext:fetchNext,hasNext:hasNext,isFetching:isFetching,results:widgetProducts.products.slice(0,offset),totalResultCount:widgetProducts.totalProductCount};};
package/page/index.js CHANGED
@@ -1,2 +1 @@
1
- /** @module page */export*from"./actions";export*from"./components";export*from"./constants";// eslint-disable-next-line import/export
2
- export*from"./selectors";
1
+ /** @module page */export*from"./actions";export*from"./components";export*from"./constants";export*from"./selectors";
@@ -0,0 +1,15 @@
1
+ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import{produce}from'immer';import{APP_WILL_START}from'@shopgate/engage/core/constants';import{REQUEST_PAGE_CONFIG_V2,RECEIVE_PAGE_CONFIG_V2,ERROR_PAGE_CONFIG_V2,PAGE_STATE_LIFETIME}from"../constants";var customWidgetRegex=/<!\x2D\x2DWidget((?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)\x2D\x2D>/gm;/**
2
+ * Decodes entities from a HTML string
3
+ * @param {string} html HTML string to decode
4
+ * @returns {string}
5
+ */var decodeHTMLEntities=function decodeHTMLEntities(){var html=arguments.length>0&&arguments[0]!==undefined?arguments[0]:'';var textarea=document.createElement('textarea');textarea.innerHTML=html;return textarea.value;};/**
6
+ * @param {Object} data The page data object
7
+ * @returns {Object} The sanitized page data
8
+ */var transformCustomLegacyWidgets=function transformCustomLegacyWidgets(data){var _data$dropzones;if(!Array.isArray(data===null||data===void 0?void 0:(_data$dropzones=data.dropzones)===null||_data$dropzones===void 0?void 0:_data$dropzones.cmsWidgetList)){return data;}var cmsWidgetList=data.dropzones.cmsWidgetList;var transformedWidgets=cmsWidgetList.map(function(widget){var _widget$widgetConfig;if(widget.widgetConfigDefinitionCode!=='@shopgate/widgets/htmlWidget'||!(widget===null||widget===void 0?void 0:(_widget$widgetConfig=widget.widgetConfig)===null||_widget$widgetConfig===void 0?void 0:_widget$widgetConfig.html)){return widget;}var content=decodeHTMLEntities(widget.widgetConfig.html.trim());if(content.startsWith('<!--Widget')){try{var settings=customWidgetRegex.exec(content);customWidgetRegex.lastIndex=0;if(settings[0]===content){var customLegacyWidget=JSON.parse(settings[1]);// Convert legacy widget data to the new format
9
+ return _extends({},widget,{widgetConfig:customLegacyWidget.settings||{},widgetConfigDefinitionCode:customLegacyWidget.type||'',isCustomLegacyWidget:true});}}catch(err){// Nothing to do here
10
+ }}return widget;});return _extends({},data,{dropzones:_extends({},data.dropzones,{cmsWidgetList:transformedWidgets})});};var defaultState={};/**
11
+ * Stores state of the v2 implementation of pages.
12
+ * @param {Object} [state={}] The current state.
13
+ * @param {Object} action The action object.
14
+ * @returns {Object} The new state.
15
+ */export function pageV2(){var state=arguments.length>0&&arguments[0]!==undefined?arguments[0]:defaultState;var action=arguments.length>1?arguments[1]:undefined;/* eslint-disable no-param-reassign */var producer=produce(function(draft){switch(action.type){case REQUEST_PAGE_CONFIG_V2:{var pageType=action.pageType,pageSlug=action.pageSlug;draft[pageType]=draft[pageType]||{};draft[pageType][pageSlug]={data:null,isFetching:true,expires:0};break;}case RECEIVE_PAGE_CONFIG_V2:{var _pageType=action.pageType,_pageSlug=action.pageSlug,data=action.data;draft[_pageType]=draft[_pageType]||{};draft[_pageType][_pageSlug]={data:transformCustomLegacyWidgets(data),isFetching:false,expires:Date.now()+PAGE_STATE_LIFETIME};break;}case ERROR_PAGE_CONFIG_V2:{var _pageType2=action.pageType,_pageSlug2=action.pageSlug;draft[_pageType2]=draft[_pageType2]||{};draft[_pageType2][_pageSlug2]={data:null,isFetching:false};break;}case APP_WILL_START:{Object.keys(draft).forEach(function(pageType){Object.keys(draft[pageType]).forEach(function(pageCode){draft[pageType][pageCode].expires=0;});});break;}default:break;}});/* eslint-enable no-param-reassign */return producer(state);}
@@ -1,7 +1,61 @@
1
- import{createSelector}from'reselect';import{makeGetMenu,makeGetIsFetchingMenu}from'@shopgate/engage/core/selectors';import{LEGAL_MENU}from'@shopgate/engage/core/constants';import{hasNewServices}from'@shopgate/engage/core';import{PRIVACY_PATH}from"../constants";export*from'@shopgate/pwa-common/selectors/page';/**
1
+ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(Object.prototype.hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;};return _extends.apply(this,arguments);}import{createSelector}from'reselect';import{makeGetMenu,makeGetIsFetchingMenu,getEnableCms2ForAllShoppers}from'@shopgate/engage/core/selectors';import{getFulfillmentParams,getPopulatedProductsResult,SHOPGATE_CATALOG_GET_HIGHLIGHT_PRODUCTS}from'@shopgate/engage/product';import{getProductState}from'@shopgate/engage/product/selectors/product';import{LEGAL_MENU,SORT_PRICE_ASC,SORT_PRICE_DESC}from'@shopgate/engage/core/constants';import{hasNewServices,transformDisplayOptions,generateResultHash}from'@shopgate/engage/core/helpers';import{getIsCMS2PreviewEnabled}from'@shopgate/engage/development/selectors';import{makeGetPageConfigById}from'@shopgate/pwa-common/selectors/page';import{PRIVACY_PATH}from"../constants";export*from'@shopgate/pwa-common/selectors/page';/**
2
2
  * Creates a selector that retrieves the privacy policy link.
3
3
  *
4
4
  * When the new services are active, the link is extracted from the "shopgate.cms.getMenu" response.
5
5
  * Otherwise it's a static link to the legacy privacy page.
6
6
  * @returns {string|null}
7
- */export var makeGetPrivacyPolicyLink=function makeGetPrivacyPolicyLink(){var getMenu=makeGetMenu(LEGAL_MENU);var getIsFetchingMenu=makeGetIsFetchingMenu(LEGAL_MENU);return createSelector(getMenu,getIsFetchingMenu,function(menu,fetching){if(!hasNewServices()){return PRIVACY_PATH;}if(fetching||!menu){return null;}var entry=menu.find(function(item){return item.url.includes('privacy');})||{};return(entry===null||entry===void 0?void 0:entry.url)||null;});};
7
+ */export var makeGetPrivacyPolicyLink=function makeGetPrivacyPolicyLink(){var getMenu=makeGetMenu(LEGAL_MENU);var getIsFetchingMenu=makeGetIsFetchingMenu(LEGAL_MENU);return createSelector(getMenu,getIsFetchingMenu,function(menu,fetching){if(!hasNewServices()){return PRIVACY_PATH;}if(fetching||!menu){return null;}var entry=menu.find(function(item){return item.url.includes('privacy');})||{};return(entry===null||entry===void 0?void 0:entry.url)||null;});};/**
8
+ * @param {Object} state The current application state.
9
+ * @return {Function} A selector function that retrieves the pageV2 state.
10
+ */var getPageV2State=function getPageV2State(state){return state.pageV2;};/**
11
+ * List of available page types.
12
+ * @typedef {'cms' | 'category'} PageType
13
+ */ /**
14
+ * List of available dropzone types.
15
+ * @typedef {'cmsWidgetList'} DropzoneType
16
+ */ /**
17
+ * Creates a selector that retrieves page data based on the type and slug.
18
+ * @param {Object} params The selector params
19
+ * @param {PageType} [params.type] The type of the page.
20
+ * @param {string|null} [params.slug=null] The slug of the page (optional).
21
+ * @returns {Function} A selector function that retrieves the page data.
22
+ */export var makeGetPage=function makeGetPage(_ref){var _ref$type=_ref.type,type=_ref$type===void 0?'cms':_ref$type,_ref$slug=_ref.slug,slug=_ref$slug===void 0?null:_ref$slug;return createSelector(getPageV2State,function(pageState){if(type&&slug){var _pageState$type;return((_pageState$type=pageState[type])===null||_pageState$type===void 0?void 0:_pageState$type[slug])||null;}return pageState[type]||null;});};/**
23
+ * Creates a selector that retrieves the widget list from a page based on the type, slug and
24
+ * and dropzone name.
25
+ * @param {Object} params The selector params
26
+ * @param {PageType} [params.type='cms'] The type of the page.
27
+ * @param {DropzoneType} [params.dropzone='cmsWidgetList'] The dropzone name to retrieve the widget
28
+ * list from.
29
+ * @param {string|null} [params.slug=null] The slug of the page (optional).
30
+ * @returns {Function} A selector function that retrieves the widget list.
31
+ */export var makeGetWidgetsFromPage=function makeGetWidgetsFromPage(_ref2){var _ref2$type=_ref2.type,type=_ref2$type===void 0?'cms':_ref2$type,_ref2$slug=_ref2.slug,slug=_ref2$slug===void 0?null:_ref2$slug,_ref2$dropzone=_ref2.dropzone,dropzone=_ref2$dropzone===void 0?'cmsWidgetList':_ref2$dropzone;var getPage=makeGetPage({type:type,slug:slug});return createSelector(getPage,function(page){var _ref3,_page$data,_page$data$dropzones;if(!page){return undefined;}return(_ref3=(_page$data=page.data)===null||_page$data===void 0?void 0:(_page$data$dropzones=_page$data.dropzones)===null||_page$data$dropzones===void 0?void 0:_page$data$dropzones[dropzone])!==null&&_ref3!==void 0?_ref3:[];});};/**
32
+ * Determines whether the new CMS version 2 is enabled.
33
+ */export var getIsCms2Enabled=createSelector(getEnableCms2ForAllShoppers,getIsCMS2PreviewEnabled,function(shopSettingEnabled,previewEnabled){return shopSettingEnabled||previewEnabled;});/**
34
+ * Creates a selector that retrieves unified CMS page data. Depending on the CMS version,
35
+ * the data is retrieved from different sources, but returned in a consistent format.
36
+ * @param {Object} params The selector parameters.
37
+ * @param {string} params.slug The slug of the page.
38
+ * @returns {Function} A selector function that retrieves the unified CMS page data.
39
+ */export var makeGetUnifiedCMSPageData=function makeGetUnifiedCMSPageData(_ref4){var slug=_ref4.slug;var getPageV2=makeGetPage({type:'cms',slug:slug});var getPageV1=makeGetPageConfigById({pageId:slug});return createSelector(getIsCms2Enabled,getPageV1,getPageV2,function(isCms2Enabled,pageV1,pageV2){var _ref8,_ref9;if(isCms2Enabled){var _ref5,_ref6,_pageV2$data,_pageV2$data2,_ref7,_pageV2$data3,_pageV2$data3$dropzon;if(!pageV2)return undefined;return{isFetching:(_ref5=pageV2===null||pageV2===void 0?void 0:pageV2.isFetching)!==null&&_ref5!==void 0?_ref5:false,expires:(_ref6=pageV2===null||pageV2===void 0?void 0:pageV2.expires)!==null&&_ref6!==void 0?_ref6:null,title:(pageV2===null||pageV2===void 0?void 0:(_pageV2$data=pageV2.data)===null||_pageV2$data===void 0?void 0:_pageV2$data.pageTitle)||(pageV2===null||pageV2===void 0?void 0:(_pageV2$data2=pageV2.data)===null||_pageV2$data2===void 0?void 0:_pageV2$data2.name)||'',widgets:(_ref7=pageV2===null||pageV2===void 0?void 0:(_pageV2$data3=pageV2.data)===null||_pageV2$data3===void 0?void 0:(_pageV2$data3$dropzon=_pageV2$data3.dropzones)===null||_pageV2$data3$dropzon===void 0?void 0:_pageV2$data3$dropzon['cmsWidgetList'])!==null&&_ref7!==void 0?_ref7:[],cmsVersion:2};}if(!pageV1)return undefined;return{isFetching:(_ref8=pageV1===null||pageV1===void 0?void 0:pageV1.isFetching)!==null&&_ref8!==void 0?_ref8:false,expires:(_ref9=pageV1===null||pageV1===void 0?void 0:pageV1.expires)!==null&&_ref9!==void 0?_ref9:null,title:(pageV1===null||pageV1===void 0?void 0:pageV1.title)||'',widgets:(pageV1===null||pageV1===void 0?void 0:pageV1.widgets)||[],cmsVersion:1};});};/**
40
+ * Creates a selector that generates a hash to select results for widget products.
41
+ * @param {'searchTerm' | 'productIds' | 'brand' | 'category' |'highlights'} type Type of the
42
+ * request to make.
43
+ * @param {Object} options Request options
44
+ * @param {string} id Unique identifier to find the result in the state.
45
+ * @returns {Function} A selector function that generates a hash for the widget products result.
46
+ */var makeGetWidgetProductsResultHash=function makeGetWidgetProductsResultHash(type,options,id){var value=options.value,sort=options.sort,useDefaultRequestForProductIds=options.useDefaultRequestForProductIds,productIdType=options.productIdType;var transformedSort=transformDisplayOptions(sort);return createSelector(getFulfillmentParams,function(fulfillmentParams){var _hashParams;var hashParams={};switch(type){case'highlights':hashParams={id:id,pipeline:SHOPGATE_CATALOG_GET_HIGHLIGHT_PRODUCTS,sort:transformedSort};break;case'searchTerm':case'brand':hashParams=_extends({id:id,searchPhrase:value,sort:transformedSort},fulfillmentParams);break;case'productIds':hashParams=_extends({id:id,productIds:value,productIdType:productIdType},!useDefaultRequestForProductIds&&{sort:transformedSort},{},fulfillmentParams);break;case'category':hashParams=_extends({id:id,categoryId:value,sort:transformedSort},fulfillmentParams);break;default:}return generateResultHash(hashParams,!!((_hashParams=hashParams)===null||_hashParams===void 0?void 0:_hashParams.sort),false);});};/**
47
+ * @param {'searchTerm' | 'productIds' | 'brand' | 'category' |'highlights'} type Type of the
48
+ * request to make.
49
+ * @param {Object} options Request options
50
+ * @param {string} id Unique identifier to find the result in the state.
51
+ * @returns {Function} A selector function that retrieves the widget products result by hash.
52
+ */var makeGetWidgetProductResultsByHash=function makeGetWidgetProductResultsByHash(type,options,id){var getWidgetProductResultsHash=makeGetWidgetProductsResultHash(type,options,id);return createSelector(getProductState,getWidgetProductResultsHash,function(productState,hash){return productState.resultsByHash[hash];});};/**
53
+ * Creates a selector that collects products for a widget.
54
+ * @param {'searchTerm' | 'productIds' | 'brand' | 'category' |'highlights'} type Type of the
55
+ * request to make.
56
+ * @param {Object} options Request options
57
+ * @param {string} id Unique identifier to find the result in the state.
58
+ * @returns {Function} A selector function that collects products for a widget.
59
+ */export var makeGetWidgetProducts=function makeGetWidgetProducts(type,options,id){var getWidgetProductResultsHash=makeGetWidgetProductsResultHash(type,options,id);var getWidgetProductResultsByHash=makeGetWidgetProductResultsByHash(type,options,id);return createSelector(function(state){return state;},function(state,props){return props!==null&&props!==void 0?props:{};},getWidgetProductResultsHash,getWidgetProductResultsByHash,function(state,props,resultsHash,resultsByHash){var result=_extends({isFetching:(resultsByHash===null||resultsByHash===void 0?void 0:resultsByHash.isFetching)||false},getPopulatedProductsResult(state,props,resultsHash,resultsByHash));// Since the getProducts pipeline does not support sorting when a product ID list is
60
+ // provided, we need to sort the products manually here.
61
+ if(type==='productIds'){if(options.sort===SORT_PRICE_ASC){result.products=result.products.sort(function(p1,p2){return p1.price.unitPrice-p2.price.unitPrice;});}if(options.sort===SORT_PRICE_DESC){result.products=result.products.sort(function(p1,p2){return p2.price.unitPrice-p1.price.unitPrice;});}}return result;});};
@@ -0,0 +1,4 @@
1
+ import{appWillStart$}from'@shopgate/engage/core/streams';/**
2
+ * Page subscriptions.
3
+ * @param {Function} subscribe The subscribe function.
4
+ */export default function page(subscribe){subscribe(appWillStart$,function(){});}
@@ -0,0 +1,4 @@
1
+ import React from'react';import{CategoryList}from'@shopgate/engage/category/components';import{makeStyles}from'@shopgate/engage/styles';import{useCategoryListWidget}from"./hooks";import WidgetHeadline from"../../components/WidgetHeadline";var useStyles=makeStyles()(function(theme){return{headline:{paddingBottom:theme.spacing(0)}};});/**
2
+ * The CategoryListWidget is used to display category lists.
3
+ * @returns {JSX.Element}
4
+ */var CategoryListWidget=function CategoryListWidget(){var _useStyles=useStyles(),classes=_useStyles.classes;var _useCategoryListWidge=useCategoryListWidget(),parentCategory=_useCategoryListWidge.parentCategory,categories=_useCategoryListWidge.categories,showImages=_useCategoryListWidge.showImages,showHeadline=_useCategoryListWidge.showHeadline,headline=_useCategoryListWidge.headline;if(!categories){return null;}return React.createElement(React.Fragment,null,showHeadline&&headline&&categories.length?React.createElement(WidgetHeadline,{headline:headline,className:classes.headline}):null,React.createElement(CategoryList,{categories:categories,parentCategory:parentCategory,showLeftSideImages:showImages}));};export default CategoryListWidget;
@@ -0,0 +1,16 @@
1
+ import _camelCase from"lodash/camelCase";import{useEffect,useMemo}from'react';import{useSelector,useDispatch}from'react-redux';import{getCategory}from'@shopgate/pwa-common-commerce/category/selectors';import{fetchCategoryOrRootCategories}from'@shopgate/engage/category/actions';import{useWidget}from'@shopgate/engage/page/hooks';import{getCategoriesById}from"./selectors";/**
2
+ * @typedef {Object} CategoryListWidgetConfig
3
+ * @property {string} category The parent category ID to display categories for.
4
+ * @property {string} [sort] The sort order for categories
5
+ * @property {boolean} [showImages] Whether to display images for categories.
6
+ * @property {boolean} [showHeadline] Whether to show the headline.
7
+ * @property {Object} [headline] The headline to be displayed.
8
+ */ /**
9
+ * @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
10
+ * .useWidget<CategoryListWidgetConfig> >} UseWidgetReturnType
11
+ */ // eslint-disable-next-line valid-jsdoc
12
+ /**
13
+ * Hook to access the Category List widget configuration and data.
14
+ */export var useCategoryListWidget=function useCategoryListWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;var dispatch=useDispatch();var category=config.category,sort=config.sort,showImages=config.showImages,_config$showHeadline=config.showHeadline,showHeadline=_config$showHeadline===void 0?false:_config$showHeadline,headline=config.headline;var sortCC=useMemo(function(){return _camelCase(sort);},[sort]);// Get the parent category object from the selected category
15
+ var parentCategory=useSelector(function(state){return category?getCategory(state,{categoryId:category}):null;});// Get category children of the selected category (pipeline handles sorting)
16
+ var categories=useSelector(function(state){return typeof category==='string'?getCategoriesById(state,{categoryId:category}):null;});var sortedCategories=useMemo(function(){if(!categories){return[];}if(sortCC==='relevance'){return categories;}var isAsc=sortCC==='nameAsc';return[].concat(categories).sort(function(a,b){return a.name.localeCompare(b.name,undefined,{sensitivity:'base'})*(isAsc?1:-1);});},[categories,sortCC]);useEffect(function(){dispatch(fetchCategoryOrRootCategories(category));},[category,dispatch]);return{parentCategory:parentCategory,showImages:showImages,categories:sortedCategories,showHeadline:showHeadline,headline:headline};};
@@ -0,0 +1 @@
1
+ export{default}from"./CategoryList";
@@ -0,0 +1,8 @@
1
+ import{createSelector}from'reselect';import{getCategoryChildren,getRootCategories}from'@shopgate/engage/category/selectors';/**
2
+ * Retrieves categories from the state.
3
+ * If no category id is passed, root-categories will be returned.
4
+ * @param {Object} state The application state.
5
+ * @param {Object} props The component props.
6
+ * @returns {Object[]} The categories collection.
7
+ */export var getCategoriesById=createSelector(getCategoryChildren,getRootCategories,function(state,props){return props.categoryId;},function(childCategories,rootCategories,categoryId){// Check if we have to handle the root-category
8
+ if(!categoryId&&rootCategories){return rootCategories;}return childCategories;});
@@ -0,0 +1,5 @@
1
+ import React from'react';import{HtmlSanitizer}from'@shopgate/engage/components';import{makeStyles}from'@shopgate/engage/styles';import{themeConfig}from'@shopgate/engage';import{useHtmlWidget}from"./hooks";var colors=themeConfig.colors;var useStyles=makeStyles()({root:{' h1, h2, h3, h4, h5, h6, p, ul, ol':{margin:'1rem 0'},' h1, h2, h3, h4, h5, h6':{fontWeight:600},' h1':{fontSize:'1.5rem'},' h2':{fontSize:'1.25rem'},' h3':{fontSize:'1.1rem'},' h4, h5, h6':{fontSize:'1rem'},' ol, ul':{paddingLeft:'1rem'},' ol > li':{listStyle:'decimal'},' ul > li':{listStyle:'disc'},' img':{display:'initial'},' img[style*="float: left"], img[style*="float:left"], img.pull-left':{marginRight:'1rem'},' img[style*="float: right"], img[style*="float:right"], img.pull-right':{marginLeft:'1rem'},' code, pre':{whiteSpace:'pre-wrap'},' blockquote, q':{paddingLeft:'1rem',margin:'2rem 0',borderLeft:".25rem solid ".concat(colors.shade6),fontStyle:'italic'},' > :first-child':{marginTop:0},// Clearfix for floated widget content
2
+ ':after':{clear:'both',content:'.',display:'block',visibility:'hidden',height:0}}});/**
3
+ * The HtmlWidget component is used to display html code.
4
+ * @returns {JSX.Element}
5
+ */var HtmlWidget=function HtmlWidget(){var _useStyles=useStyles(),classes=_useStyles.classes;var _useHtmlWidget=useHtmlWidget(),html=_useHtmlWidget.html;return React.createElement(HtmlSanitizer,{settings:{html:html},processStyles:true,className:classes.root},html);};export default HtmlWidget;
@@ -0,0 +1,12 @@
1
+ import{useWidget}from'@shopgate/engage/page/hooks';/**
2
+ * @typedef {Object} HtmlWidgetConfig
3
+ * @property {string} [html] - The HTML content to render.
4
+ * @property {string} [internalDescription] - Internal description for the widget.
5
+ */ /**
6
+ * @typedef {Object} UseHtmlWidgetReturnType
7
+ * @property {string} [html] - The HTML content to render.
8
+ * @property {string} [internalDescription] - Internal description for the widget.
9
+ */ /**
10
+ * Hook to access the html widget configuration.
11
+ * @returns {UseHtmlWidgetReturnType} the html widget configuration
12
+ */export var useHtmlWidget=function useHtmlWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;var html=config.html;return{html:html};};
@@ -0,0 +1 @@
1
+ export{default}from"./HTML";
@@ -0,0 +1,4 @@
1
+ import React from'react';import WidgetHeadline from"../../components/WidgetHeadline";import{useWidget}from"../../hooks";/**
2
+ * The HeadlineWidget is used to display a headline text.
3
+ * @returns {JSX.Element}
4
+ */var Headline=function Headline(){var _useWidget=useWidget(),config=_useWidget.config;var headline=config.headline;if(!headline)return null;return React.createElement(WidgetHeadline,{headline:headline});};export default Headline;
@@ -0,0 +1 @@
1
+ export{default}from"./Headline";