@shopgate/engage 7.27.3-alpha.6 → 7.27.3-alpha.8
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.
- package/components/ResponsiveContainer/breakpoints.js +2 -2
- package/components/View/components/Content/style.js +1 -1
- package/components/View/context.js +1 -1
- package/core/constants/index.js +1 -7
- package/core/contexts/ThemeResourcesContext.d.ts +1 -10
- package/core/contexts/ThemeResourcesContext.js +1 -1
- package/core/helpers/scrollContainer.js +2 -2
- package/core/hocs/withThemeResources.js +1 -4
- package/core/hooks/events/index.js +1 -1
- package/core/hooks/useThemeResources.js +5 -6
- package/core/providers/ThemeResourcesProvider.js +5 -9
- package/locations/subscriptions.js +2 -2
- package/package.json +7 -9
- package/page/components/index.js +1 -1
- package/page/constants/index.js +1 -5
- package/page/index.js +2 -1
- package/page/selectors/index.js +2 -48
- package/product/components/index.js +1 -1
- package/styles/helpers/index.js +1 -1
- package/styles/helpers/setPageBackgroundColor.js +2 -2
- package/styles/index.js +1 -1
- package/tracking/selectors/cookieConsent.js +2 -2
- package/core/hooks/events/usePressHandler.js +0 -38
- package/page/action-creators/index.js +0 -22
- package/page/components/Widgets/Overlay.js +0 -51
- package/page/components/Widgets/Tooltip.js +0 -22
- package/page/components/Widgets/Widget.js +0 -15
- package/page/components/Widgets/WidgetContext.d.ts +0 -42
- package/page/components/Widgets/WidgetContext.js +0 -9
- package/page/components/Widgets/WidgetProvider.js +0 -8
- package/page/components/Widgets/Widgets.js +0 -11
- package/page/components/Widgets/WidgetsPreviewContext.js +0 -9
- package/page/components/Widgets/WidgetsPreviewProvider.js +0 -8
- package/page/components/Widgets/constants.js +0 -4
- package/page/components/Widgets/events.js +0 -23
- package/page/components/Widgets/helpers.js +0 -23
- package/page/components/Widgets/hooks.js +0 -69
- package/page/components/Widgets/index.js +0 -1
- package/page/components/Widgets/types.d.ts +0 -127
- package/page/constants/actionTypes.js +0 -1
- package/page/hooks/index.d.ts +0 -60
- package/page/hooks/index.js +0 -25
- package/page/reducers/index.js +0 -6
- package/page/subscriptions/index.js +0 -4
- package/page/widgets/Placeholder/Placeholder.js +0 -5
- package/page/widgets/Placeholder/hooks.js +0 -12
- package/page/widgets/Placeholder/index.js +0 -1
- package/page/widgets/ProductList/ProductList.js +0 -5
- package/page/widgets/ProductList/hooks.js +0 -25
- package/page/widgets/ProductList/index.js +0 -1
- package/page/widgets/index.js +0 -1
- package/page/widgets/widgets.json +0 -8
- package/product/components/ProductGrid/components/Item/components/ItemDetails/index.js +0 -8
- package/product/components/ProductGrid/components/Item/components/ItemDetails/spec.js +0 -1
- package/product/components/ProductGrid/components/Item/components/ItemDiscount/index.js +0 -5
- package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/index.js +0 -5
- package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/spec.js +0 -1
- package/product/components/ProductGrid/components/Item/components/ItemImage/index.js +0 -5
- package/product/components/ProductGrid/components/Item/components/ItemImage/spec.js +0 -1
- package/product/components/ProductGrid/components/Item/components/ItemName/index.js +0 -5
- package/product/components/ProductGrid/components/Item/components/ItemName/spec.js +0 -1
- package/product/components/ProductGrid/components/Item/components/ItemPrice/index.js +0 -5
- package/product/components/ProductGrid/components/Item/components/ItemPrice/spec.js +0 -1
- package/product/components/ProductGrid/components/Item/index.js +0 -7
- package/product/components/ProductGrid/components/Iterator/index.js +0 -5
- package/product/components/ProductGrid/components/Layout/index.js +0 -5
- package/product/components/ProductGrid/index.js +0 -22
- package/product/components/ProductGrid/spec.js +0 -1
- package/styles/helpers/color.js +0 -23
- package/styles/index.d.ts +0 -17
- package/styles/theme/createTheme/createBreakpoints.d.ts +0 -114
- package/styles/theme/createTheme/createBreakpoints.js +0 -41
- package/styles/theme/createTheme/createSpacing.d.ts +0 -23
- package/styles/theme/createTheme/createSpacing.js +0 -14
- package/styles/theme/createTheme/index.d.ts +0 -19
- package/styles/theme/createTheme/index.js +0 -5
- package/styles/theme/createTheme/transitions.d.ts +0 -100
- package/styles/theme/createTheme/transitions.js +0 -26
- package/styles/theme/createTheme/zIndex.d.ts +0 -12
- package/styles/theme/createTheme/zIndex.js +0 -3
- package/styles/theme/hooks/index.d.ts +0 -4
- package/styles/theme/hooks/index.js +0 -1
- package/styles/theme/hooks/useActiveBreakpoint.d.ts +0 -18
- package/styles/theme/hooks/useActiveBreakpoint.js +0 -4
- package/styles/theme/hooks/useMediaQuery.d.ts +0 -33
- package/styles/theme/hooks/useMediaQuery.js +0 -20
- package/styles/theme/hooks/useResponsiveValue.d.ts +0 -27
- package/styles/theme/hooks/useResponsiveValue.js +0 -4
- package/styles/theme/hooks/useTheme.d.ts +0 -8
- package/styles/theme/hooks/useTheme.js +0 -4
- package/styles/theme/index.d.ts +0 -8
- package/styles/theme/index.js +0 -1
- package/styles/theme/providers/ActiveBreakpointProvider.d.ts +0 -21
- package/styles/theme/providers/ActiveBreakpointProvider.js +0 -13
- package/styles/theme/providers/ThemeProvider.d.ts +0 -18
- package/styles/theme/providers/ThemeProvider.js +0 -7
- package/styles/tss/index.js +0 -3
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { type Context } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
type WidgetDefinitionLayout,
|
|
4
|
-
type WidgetDefinitionVisibility,
|
|
5
|
-
type WidgetDefinition,
|
|
6
|
-
} from './types'
|
|
7
|
-
|
|
8
|
-
export { WidgetDefinition } from './types';
|
|
9
|
-
|
|
10
|
-
export interface WidgetContextType<C = Record<string, any>> {
|
|
11
|
-
/**
|
|
12
|
-
* The unique code of the widget instance
|
|
13
|
-
*/
|
|
14
|
-
code: string;
|
|
15
|
-
/**
|
|
16
|
-
* The name of the widget
|
|
17
|
-
*/
|
|
18
|
-
name: string;
|
|
19
|
-
/**
|
|
20
|
-
* The widget configuration
|
|
21
|
-
*/
|
|
22
|
-
config: C;
|
|
23
|
-
/**
|
|
24
|
-
* The widget layout settings
|
|
25
|
-
*/
|
|
26
|
-
layout: WidgetDefinitionLayout;
|
|
27
|
-
/**
|
|
28
|
-
* The widget visibility settings
|
|
29
|
-
*/
|
|
30
|
-
visibility: WidgetDefinitionVisibility;
|
|
31
|
-
/**
|
|
32
|
-
* Whether the widget is rendered in preview mode
|
|
33
|
-
*/
|
|
34
|
-
isPreview: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* React context for widgets.
|
|
39
|
-
*/
|
|
40
|
-
declare const WidgetContext: Context<WidgetContextType>;
|
|
41
|
-
|
|
42
|
-
export default WidgetContext;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import{createContext}from'react';/**
|
|
2
|
-
* @typedef {import('./Widgets.jsx').WidgetDefinition} WidgetDefinition
|
|
3
|
-
*/ /**
|
|
4
|
-
* @typedef {Object} WidgetContextType
|
|
5
|
-
* @property {WidgetDefinition['code']} code The unique widget code.
|
|
6
|
-
* @property {WidgetDefinition['widgetConfig']} config The widget configuration.
|
|
7
|
-
* @property {WidgetDefinition['layout']} layout The widget layout settings.
|
|
8
|
-
* @property {WidgetDefinition['visibility']} visibility The widget visibility settings.
|
|
9
|
-
*/ /** @type {React.Context<WidgetContextType>} */export var WidgetContext=createContext({});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React,{useMemo}from'react';import PropTypes from'prop-types';import{WidgetContext}from"./WidgetContext";/** @typedef {import('./WidgetContext').WidgetContextType} WidgetContextType */ /** @typedef {import('./WidgetContext').WidgetDefinition} WidgetDefinition */ /**
|
|
2
|
-
* The WidgetProvider component provides the context for a single widget.
|
|
3
|
-
* @param {Object} props The component props.
|
|
4
|
-
* @param {WidgetDefinition} props.definition The widget definition data.
|
|
5
|
-
* @param {boolean} props.isPreview Whether the widget is in preview mode.
|
|
6
|
-
* @param {React.ReactNode} props.children The child components to render.
|
|
7
|
-
* @returns {JSX.Element}
|
|
8
|
-
*/var WidgetProvider=function WidgetProvider(_ref){var children=_ref.children,definition=_ref.definition,isPreview=_ref.isPreview;/** @type {WidgetContextType} */var value=useMemo(function(){var widgetConfig=definition.widgetConfig,layout=definition.layout,visibility=definition.visibility,code=definition.code,widgetConfigDefinitionCode=definition.widgetConfigDefinitionCode;return{code:code,name:widgetConfigDefinitionCode,config:widgetConfig,layout:layout,visibility:visibility,isPreview:isPreview};},[definition,isPreview]);return React.createElement(WidgetContext.Provider,{value:value},children);};export default WidgetProvider;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
function _defineProperty(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true});}else{obj[key]=value;}return obj;}import React,{useMemo,useRef}from'react';import PropTypes from'prop-types';import{makeStyles}from'@shopgate/engage/styles';import{useRoute,useThemeWidgets}from'@shopgate/engage/core/hooks';import{PAGE_PREVIEW_PATTERN}from'@shopgate/engage/page/constants';import{ConditionalWrapper}from'@shopgate/engage/components';import WidgetsPreviewProvider from"./WidgetsPreviewProvider";import Widget from"./Widget";import Overlay from"./Overlay";import{usePreviewIframeCommunication}from"./hooks";/**
|
|
2
|
-
* @typedef {import('./types').WidgetDefinition} WidgetDefinition
|
|
3
|
-
*/var PLACEHOLDER_COMPONENT='@shopgate/widgetsInternal/Placeholder';var useStyles=makeStyles()({preview:{'& *':{scrollbarWidth:'thin'}}});/**
|
|
4
|
-
* The Widgets component renders a list of widgets.
|
|
5
|
-
* @param {Object} props The component props.
|
|
6
|
-
* @param {Array<WidgetDefinition>} props.widgets The list of widgets to render.
|
|
7
|
-
* @returns {JSX.Element}
|
|
8
|
-
*/var Widgets=function Widgets(_ref){var _ref$widgets=_ref.widgets,widgetsProp=_ref$widgets===void 0?[]:_ref$widgets;var _useStyles=useStyles(),classes=_useStyles.classes,cx=_useStyles.cx;var _useRoute=useRoute(),pattern=_useRoute.pattern;var widgetsRef=useRef(null);var isPreview=pattern===PAGE_PREVIEW_PATTERN;var widgetComponents=useThemeWidgets('v2');usePreviewIframeCommunication(isPreview);// Create sanitized widgets array that only includes widgets with valid components.
|
|
9
|
-
var widgets=useMemo(function(){if(isPreview){// All widgets are allowed in preview mode.
|
|
10
|
-
return widgetsProp;}// Remove widgets that do not have a valid component.
|
|
11
|
-
return widgetsProp.filter(function(widget){return!!widgetComponents[widget.widgetConfigDefinitionCode];});},[isPreview,widgetComponents,widgetsProp]);if(!Array.isArray(widgets)||widgets.length===0){return null;}return React.createElement(ConditionalWrapper,{condition:isPreview,wrapper:function wrapper(children){return React.createElement(WidgetsPreviewProvider,null,children,React.createElement(Overlay,{containerRef:widgetsRef}));}},React.createElement("div",{className:cx('engage__widgets',_defineProperty({},classes.preview,isPreview)),ref:widgetsRef},widgets.map(function(widget){var component=widgetComponents[widget.widgetConfigDefinitionCode]||widgetComponents[PLACEHOLDER_COMPONENT];return React.createElement(Widget,{key:widget.code,definition:widget,isPreview:isPreview,component:component});})));};Widgets.defaultProps={widgets:null};export default Widgets;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import _noop from"lodash/noop";import{createContext}from'react';/**
|
|
2
|
-
* @callback SetActiveWidget
|
|
3
|
-
* @param {string} code The code of the widget to set as active.
|
|
4
|
-
* @param {boolean} [highlight=false] Whether to highlight the widget after setting it as active.
|
|
5
|
-
*/ /**
|
|
6
|
-
* @typedef {Object} WidgetsPreviewContextType
|
|
7
|
-
* @property {string} activeWidget The code of the currently active widget.
|
|
8
|
-
* @property {SetActiveWidget} setActiveWidget A function to set the active widget code
|
|
9
|
-
*/ /** @type {React.Context<WidgetsPreviewContextType>} */export var WidgetsPreviewContext=createContext({activeWidget:null,setActiveWidget:_noop});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
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;}import React,{useMemo,useState,useCallback}from'react';import PropTypes from'prop-types';import{useWidgetPreviewEvent,dispatchWidgetPreviewEvent}from"./events";import{WidgetsPreviewContext}from"./WidgetsPreviewContext";/**
|
|
2
|
-
* The WidgetsPreviewProvider component is used by the Widgets component when it's rendered
|
|
3
|
-
* in preview mode. It provides functionality for the Widget component that's needed when
|
|
4
|
-
* the widgets are rendered in the preview iframe.
|
|
5
|
-
* @param {Object} props The component props.
|
|
6
|
-
* @param {React.ReactNode} props.children The child components to render.
|
|
7
|
-
* @returns {JSX.Element}
|
|
8
|
-
*/var WidgetsPreviewProvider=function WidgetsPreviewProvider(_ref){var children=_ref.children;var _useState=useState(null),_useState2=_slicedToArray(_useState,2),activeWidget=_useState2[0],setActiveWidget=_useState2[1];useWidgetPreviewEvent('set-active-widget-id',function(e){setActiveWidget(e.detail.widgetCode);});var handleSetActiveWidget=useCallback(function(code){var highlight=arguments.length>1&&arguments[1]!==undefined?arguments[1]:false;setActiveWidget(code);if(highlight){dispatchWidgetPreviewEvent('highlight-widget',code);}},[]);var value=useMemo(function(){return{activeWidget:activeWidget,setActiveWidget:handleSetActiveWidget};},[activeWidget,handleSetActiveWidget]);return React.createElement(WidgetsPreviewContext.Provider,{value:value},children);};export default WidgetsPreviewProvider;
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* List of allowed origins for cms page preview iFrame communication.
|
|
3
|
-
*/export var ALLOWED_PAGE_PREVIEW_ORIGINS=['https://next.admin.shopgatedev.com','https://next.admin.shopgatepg.com','https://next.admin.shopgate.com','https://next.us.admin.shopgate.com','http://localhost:1337'];// Whether to consider vertical margins when calculating the overlay position.
|
|
4
|
-
export var CONSIDER_CONTAINER_MARGINS_ON_SCROLL_DEFAULT=false;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import{useEffect}from'react';/**
|
|
2
|
-
* @typedef {"highlight-widget"|"widget-clicked"|"set-active-widget-id"} WidgetPreviewEventName
|
|
3
|
-
*/ /**
|
|
4
|
-
* @typedef {Object} WidgetPreviewEventDetail
|
|
5
|
-
* @property {string} widgetCode The code of the widget related to the event.
|
|
6
|
-
* @property {any} [payload] Optional payload data related to the event.
|
|
7
|
-
*/ /**
|
|
8
|
-
* @callback WidgetPreviewEventHandler
|
|
9
|
-
* @param {CustomEvent<WidgetPreviewEventDetail>} event The custom event dispatched for the widget
|
|
10
|
-
* preview.
|
|
11
|
-
*/ /**
|
|
12
|
-
* Hook to listen for widget preview events.
|
|
13
|
-
* These events are dispatched in the context of iFrame communication at the widget preview.
|
|
14
|
-
* @param {WidgetPreviewEventName} eventName Name of the listened event
|
|
15
|
-
* @param {WidgetPreviewEventHandler} handler A callback function to handle the event
|
|
16
|
-
*/export var useWidgetPreviewEvent=function useWidgetPreviewEvent(eventName,handler){useEffect(function(){window.addEventListener("widget-preview-".concat(eventName),handler);return function(){window.removeEventListener("widget-preview-".concat(eventName),handler);};},[eventName,handler]);};/**
|
|
17
|
-
* Dispatches widget preview related events.
|
|
18
|
-
* Used to trigger iFrame postMessage events to the parent window or to react on incoming
|
|
19
|
-
* postMessage events from the parent window.
|
|
20
|
-
* @param {WidgetPreviewEventName} eventName Name of the event to dispatch
|
|
21
|
-
* @param {string} widgetCode Code of the widget to dispatch the event for
|
|
22
|
-
* @param {Object} [payload] Optional payload to include with the event
|
|
23
|
-
*/export var dispatchWidgetPreviewEvent=function dispatchWidgetPreviewEvent(eventName,widgetCode){var payload=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;var event=new CustomEvent("widget-preview-".concat(eventName),{detail:{widgetCode:widgetCode,payload:payload}});window.dispatchEvent(event);};
|
|
@@ -1,23 +0,0 @@
|
|
|
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
|
-
* @param {string} [from] The start date of the scheduling in ISO format.
|
|
8
|
-
* @param {string} [to] The end date of the scheduling in ISO format.
|
|
9
|
-
* @param {number} [timezoneOffset] The timezone offset in minutes. If not provided, the local
|
|
10
|
-
* timezone offset will be used.
|
|
11
|
-
*/ /**
|
|
12
|
-
* @typedef {Object} ScheduledStatus
|
|
13
|
-
* @param {boolean} isScheduled Indicates if the widget is scheduled.
|
|
14
|
-
* @param {boolean} isActive Indicates if the widget is currently active within the
|
|
15
|
-
* scheduled time frame.
|
|
16
|
-
* @param {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};}
|
|
@@ -1,69 +0,0 @@
|
|
|
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);};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{default}from"./Widgets";export{WidgetContext}from"./WidgetContext";
|
|
@@ -1,127 +0,0 @@
|
|
|
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
|
-
* Visibility settings for the widget.
|
|
59
|
-
*/
|
|
60
|
-
visibility: WidgetDefinitionVisibility;
|
|
61
|
-
/**
|
|
62
|
-
* Layout settings for the widget.
|
|
63
|
-
*/
|
|
64
|
-
layout: WidgetDefinitionLayout;
|
|
65
|
-
/**
|
|
66
|
-
* Optional metadata for the widget (only available in preview mode)
|
|
67
|
-
*/
|
|
68
|
-
meta?: {
|
|
69
|
-
/**
|
|
70
|
-
* Hidden state related data
|
|
71
|
-
*/
|
|
72
|
-
hidden: {
|
|
73
|
-
/**
|
|
74
|
-
* Whether the widget is hidden.
|
|
75
|
-
*/
|
|
76
|
-
isHidden: boolean;
|
|
77
|
-
/**
|
|
78
|
-
* Tooltip text for hidden related UI elements.
|
|
79
|
-
*/
|
|
80
|
-
tooltip: string;
|
|
81
|
-
/**
|
|
82
|
-
* Label text for hidden related UI elements.
|
|
83
|
-
*/
|
|
84
|
-
label: string;
|
|
85
|
-
};
|
|
86
|
-
/**
|
|
87
|
-
* Scheduled state related data
|
|
88
|
-
*/
|
|
89
|
-
scheduled: {
|
|
90
|
-
/**
|
|
91
|
-
* Indicates if the widget is scheduled.
|
|
92
|
-
*/
|
|
93
|
-
isScheduled: boolean;
|
|
94
|
-
/**
|
|
95
|
-
* Indicates that the widget schedule time frame is currently active.
|
|
96
|
-
*/
|
|
97
|
-
isActive: boolean;
|
|
98
|
-
/**
|
|
99
|
-
* Indicates if the scheduled time frame has expired
|
|
100
|
-
*/
|
|
101
|
-
isExpired: boolean;
|
|
102
|
-
/**
|
|
103
|
-
* Tooltip text for schedule related UI elements.
|
|
104
|
-
*/
|
|
105
|
-
tooltip: string;
|
|
106
|
-
/**
|
|
107
|
-
* Label text for schedule related UI elements.
|
|
108
|
-
*/
|
|
109
|
-
label: string;
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export interface ScheduledStatus {
|
|
115
|
-
/**
|
|
116
|
-
* Indicates if the widget is scheduled.
|
|
117
|
-
*/
|
|
118
|
-
isScheduled: boolean;
|
|
119
|
-
/**
|
|
120
|
-
* Indicates if the widget is currently hidden based on the scheduling
|
|
121
|
-
*/
|
|
122
|
-
isHidden: boolean;
|
|
123
|
-
/**
|
|
124
|
-
* Indicates if the scheduled time frame has expired.
|
|
125
|
-
*/
|
|
126
|
-
isExpired: boolean;
|
|
127
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
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';
|
package/page/hooks/index.d.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
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' | 'itemNumbers' | '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;
|
package/page/hooks/index.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
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,itemNumbers: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;// ###### 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
|
-
var _useState=useState(true),_useState2=_slicedToArray(_useState,2),hasNext=_useState2[0],setHasNext=_useState2[1];var _useState3=useState(0),_useState4=_slicedToArray(_useState3,2),offset=_useState4[0],setOffset=_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]);/**
|
|
17
|
-
* Callback to dispatch the initial fetch request for products when the hook mounts,
|
|
18
|
-
* or when its parameters change.
|
|
19
|
-
*/var fetchInitial=useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(){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
|
|
20
|
-
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
|
|
21
|
-
setOffset(limit);setHasNext(result.totalProductCount>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.
|
|
22
|
-
useEffect(function(){fetchInitial();},[fetchInitial]);/**
|
|
23
|
-
* Callback to fetch the next chunk of products when e.g. users interacted with a "Load More"
|
|
24
|
-
* button.
|
|
25
|
-
*/var fetchNext=useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(){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);setHasNext(result.totalProductCount>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/reducers/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import{produce}from'immer';import{REQUEST_PAGE_CONFIG_V2,RECEIVE_PAGE_CONFIG_V2,ERROR_PAGE_CONFIG_V2,PAGE_STATE_LIFETIME}from"../constants";var defaultState={};/**
|
|
2
|
-
* Stores state of the v2 implementation of pages.
|
|
3
|
-
* @param {Object} [state={}] The current state.
|
|
4
|
-
* @param {Object} action The action object.
|
|
5
|
-
* @returns {Object} The new state.
|
|
6
|
-
*/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: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;}default:break;}});/* eslint-enable no-param-reassign */return producer(state);}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import React from'react';import{makeStyles}from'@shopgate/engage/styles';import{usePlaceholderWidget}from"./hooks";var useStyles=makeStyles()(function(theme){return{root:{padding:theme.spacing(2),minHeight:200},name:{fontSize:14},pre:{background:'#f7f9fc',border:'1px solid #dbdde2',borderRadius:8,color:'#000',fontSize:10,overflowY:'auto',padding:theme.spacing(1)}};});/**
|
|
2
|
-
* The PlaceholderWidget component is used to display a placeholder for widget types that
|
|
3
|
-
* are not implemented yet.
|
|
4
|
-
* @returns {JSX.Element}
|
|
5
|
-
*/var PlaceholderWidget=function PlaceholderWidget(){var _useStyles=useStyles(),classes=_useStyles.classes;var _usePlaceholderWidget=usePlaceholderWidget(),code=_usePlaceholderWidget.code,name=_usePlaceholderWidget.name,config=_usePlaceholderWidget.config,layout=_usePlaceholderWidget.layout,visibility=_usePlaceholderWidget.visibility;return React.createElement("div",{className:classes.root},React.createElement("div",{className:classes.name},name),React.createElement("pre",{className:classes.pre},JSON.stringify({code:code,config:config,layout:layout,visibility:visibility},null,2)));};export default PlaceholderWidget;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import{useWidget}from'@shopgate/engage/page/hooks';/**
|
|
2
|
-
* @typedef {Object} PlaceholderWidgetConfig
|
|
3
|
-
* @property {string} foo Example property for the widget configuration.
|
|
4
|
-
* @property {number} bar Another example property for the widget configuration.
|
|
5
|
-
*/ /**
|
|
6
|
-
* @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
|
|
7
|
-
* .useWidget<PlaceholderWidgetConfig> >} HookReturnType
|
|
8
|
-
*/ /**
|
|
9
|
-
* Local example hook to demonstrate how to extend the useWidget hook with a custom type for
|
|
10
|
-
* the widget configuration.
|
|
11
|
-
* @returns {HookReturnType}
|
|
12
|
-
*/export var usePlaceholderWidget=function usePlaceholderWidget(){return useWidget();};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{default}from"./Placeholder";
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import React from'react';import{ActionButton,I18n}from'@shopgate/engage/components';import{ProductGrid}from'@shopgate/engage/product/components';import{useWidgetProducts}from'@shopgate/engage/page/hooks';import{makeStyles}from'@shopgate/engage/styles';import{useProductListWidget}from"./hooks";var useStyles=makeStyles()({root:{// Prevent that the ActionButton margin messes with the layout of the sibling widgets
|
|
2
|
-
overflow:'hidden'},grid:{'&&':{marginTop:0}}});/**
|
|
3
|
-
* The ProductListWidget is used to display product lists.
|
|
4
|
-
* @returns {JSX.Element}
|
|
5
|
-
*/var ProductListWidget=function ProductListWidget(){var _useStyles=useStyles(),classes=_useStyles.classes;var _useProductListWidget=useProductListWidget(),productsSearchType=_useProductListWidget.productsSearchType,productsSearchValue=_useProductListWidget.productsSearchValue,sort=_useProductListWidget.sort,productCount=_useProductListWidget.productCount,showLoadMore=_useProductListWidget.showLoadMore,flags=_useProductListWidget.flags;var _useWidgetProducts=useWidgetProducts({type:productsSearchType,value:productsSearchValue,limit:productCount,sort:sort}),fetchNext=_useWidgetProducts.fetchNext,hasNext=_useWidgetProducts.hasNext,isFetching=_useWidgetProducts.isFetching,results=_useWidgetProducts.results;return React.createElement("div",{className:classes.root},React.createElement(ProductGrid,{products:results,flags:flags,scope:"widgets",infiniteLoad:false,className:classes.grid}),hasNext&&showLoadMore&&React.createElement(ActionButton,{loading:isFetching,onClick:fetchNext},React.createElement(I18n.Text,{string:"common.load_more"})));};export default ProductListWidget;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import _camelCase from"lodash/camelCase";import{useMemo}from'react';import{useWidget}from'@shopgate/engage/page/hooks';/**
|
|
2
|
-
* @typedef {Object} ProductListWidgetProducts
|
|
3
|
-
* @property {"searchTerm" | "brand" | "category" | "itemNumbers"} productSelectorType Source type
|
|
4
|
-
* for the product list.
|
|
5
|
-
* @property {string} productsSearchTerm A search term to filter products by
|
|
6
|
-
* @property {string} productsBrand A brand to filter products by
|
|
7
|
-
* @property {string} productsCategory A category to filter products by
|
|
8
|
-
* @property {string} productsItemNumbers A comma-separated list of item numbers to filter products
|
|
9
|
-
* by
|
|
10
|
-
*/ /**
|
|
11
|
-
* @typedef {Object} ProductListWidgetConfig
|
|
12
|
-
* @property {ProductListWidgetProducts} products The products configuration for the widget.
|
|
13
|
-
* @property {number} productCount The number of products to display in the widget
|
|
14
|
-
* @property {"relevance" | "PriceDesc" | "PriceDesc"} sort Sort order for the products
|
|
15
|
-
* @property {boolean} loadMoreButton Whether to display a "Load more" button
|
|
16
|
-
* @property {boolean} showName Whether to display product names
|
|
17
|
-
* @property {boolean} showPrice Whether to display product prices
|
|
18
|
-
* @property {boolean} showRating Whether to display product ratings
|
|
19
|
-
*/ /**
|
|
20
|
-
* @typedef {ReturnType< typeof import('@shopgate/engage/page/hooks')
|
|
21
|
-
* .useWidget<ProductListWidgetConfig> >} UseWidgetReturnType
|
|
22
|
-
*/ // eslint-disable-next-line valid-jsdoc
|
|
23
|
-
/**
|
|
24
|
-
* Hook to access the Product List widget configuration.
|
|
25
|
-
*/export var useProductListWidget=function useProductListWidget(){/** @type {UseWidgetReturnType} */var _useWidget=useWidget(),config=_useWidget.config;var products=config.products,productCount=config.productCount,sort=config.sort,_config$loadMoreButto=config.loadMoreButton,loadMoreButton=_config$loadMoreButto===void 0?false:_config$loadMoreButto,_config$showName=config.showName,showName=_config$showName===void 0?false:_config$showName,_config$showPrice=config.showPrice,showPrice=_config$showPrice===void 0?false:_config$showPrice,_config$showRating=config.showRating,showRating=_config$showRating===void 0?false:_config$showRating;var productSelectorType=products.productSelectorType,productsBrand=products.productsBrand,productsCategory=products.productsCategory,productsItemNumbers=products.productsItemNumbers,productsSearchTerm=products.productsSearchTerm;var value=useMemo(function(){switch(productSelectorType){case'brand':return productsBrand;case'category':return productsCategory;case'itemNumbers':return productsItemNumbers.split(',').map(function(item){return item.trim();});case'searchTerm':default:return productsSearchTerm;}},[productSelectorType,productsBrand,productsCategory,productsItemNumbers,productsSearchTerm]);var flags=useMemo(function(){return{name:showName,price:showPrice,reviews:showRating};},[showName,showPrice,showRating]);return{productsSearchType:productSelectorType,productsSearchValue:value,sort:_camelCase(sort),productCount:productCount,showLoadMore:loadMoreButton,flags:flags};};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{default}from"./ProductList";
|
package/page/widgets/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export{default as PlaceholderWidget}from"./Placeholder";export{default as ProductListWidget}from"./ProductList";
|
|
@@ -1,8 +0,0 @@
|
|
|
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 React,{useMemo,memo}from'react';import PropTypes from'prop-types';import{MapPriceHint,OrderQuantityHint,EffectivityDates,Swatches,AVAILABILITY_STATE_OK,AVAILABILITY_STATE_ALERT,getProductRoute}from'@shopgate/engage/product';import{hasNewServices as checkHasNewServices,i18n}from'@shopgate/engage/core/helpers';import{Availability,Link}from'@shopgate/engage/components';import{StockInfoLists}from'@shopgate/engage/locations/components';import{makeStyles}from'@shopgate/engage/styles';import ItemName from"../ItemName";import ItemPrice from"../ItemPrice";var useStyles=makeStyles()({root:{lineHeight:1.2,':not(:empty)':{padding:'12px 0 16px'}},quantityHint:{paddingTop:8}});/**
|
|
2
|
-
* The Product Grid Item Detail component.
|
|
3
|
-
* @param {Object} props The component props.
|
|
4
|
-
* @param {Object} props.product The product.
|
|
5
|
-
* @param {Object} props.display The display object.
|
|
6
|
-
* @param {Object} [props.productListTypeMeta] Optional meta object with data from the product list
|
|
7
|
-
* @returns {JSX.Element}
|
|
8
|
-
*/var ItemDetails=function ItemDetails(_ref){var product=_ref.product,display=_ref.display,productListTypeMeta=_ref.productListTypeMeta;var productId=product.id,_product$name=product.name,name=_product$name===void 0?null:_product$name,_product$stock=product.stock,stock=_product$stock===void 0?null:_product$stock;var _useStyles=useStyles(),classes=_useStyles.classes,cx=_useStyles.cx;var hasNewServices=useMemo(function(){return checkHasNewServices();},[]);if(display&&!display.name&&!display.price&&!display.reviews){return null;}return React.createElement(Link,{className:cx(classes.root,'theme__product-grid__item__item-details'),tabIndex:0,href:getProductRoute(productId),state:_extends({title:product.name},productListTypeMeta)},React.createElement(Swatches,{productId:productId}),React.createElement(ItemName,{display:display,productId:productId,name:name}),React.createElement(MapPriceHint,{productId:productId}),React.createElement(OrderQuantityHint,{productId:productId,className:classes.quantityHint}),React.createElement(EffectivityDates,{productId:productId}),hasNewServices&&React.createElement(React.Fragment,null,React.createElement(Availability,{state:!stock||stock.orderable?AVAILABILITY_STATE_OK:AVAILABILITY_STATE_ALERT,text:i18n.text('product.available.not'),showWhenAvailable:false}),React.createElement(StockInfoLists,{product:product})),React.createElement(ItemPrice,{product:product,display:display}));};ItemDetails.defaultProps={display:null,productListTypeMeta:null};export default memo(ItemDetails);
|
|
@@ -1 +0,0 @@
|
|
|
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 React from'react';import{shallow}from'enzyme';import{hasNewServices}from'@shopgate/engage/core/helpers';import{Availability}from'@shopgate/engage/components';import{StockInfoLists}from'@shopgate/engage/locations/components';import ItemDetails from"./index";jest.mock('@shopgate/engage/product',function(){return{MapPriceHint:function MapPriceHint(){return null;},OrderQuantityHint:function OrderQuantityHint(){return null;},EffectivityDates:function EffectivityDates(){return null;},Swatches:function Swatches(){return null;},AVAILABILITY_STATE_OK:'AVAILABILITY_STATE_OK',AVAILABILITY_STATE_ALERT:'AVAILABILITY_STATE_ALERT',getProductRoute:jest.fn(function(productId){return"link-to-product/".concat(productId);})};});jest.mock('@shopgate/engage/locations/components',function(){return{StockInfoLists:function StockInfoLists(){return null;}};});jest.mock('@shopgate/engage/core/helpers',function(){return{hasNewServices:jest.fn().mockReturnValue(false),i18n:{text:function text(str){return str;}}};});jest.mock('@shopgate/engage/components');jest.mock('@shopgate/engage/core',function(){return{isIOSTheme:jest.fn().mockReturnValue(true),hasWebBridge:jest.fn().mockReturnValue(false),i18n:{text:function text(_text){return _text;}}};});jest.mock("../ItemName");jest.mock("../ItemPrice");describe('<ItemDetails />',function(){var props={product:{id:'1234',name:'Foo',price:{}}};var display={name:false,price:false,reviews:false};it('should render with minimal props',function(){var wrapper=shallow(React.createElement(ItemDetails,props));expect(wrapper).toMatchSnapshot();expect(wrapper.find(Availability).exists()).toBe(false);expect(wrapper.find(StockInfoLists).exists()).toBe(false);});it('should render additional components with new services',function(){hasNewServices.mockReturnValueOnce(true);var wrapper=shallow(React.createElement(ItemDetails,props));expect(wrapper).toMatchSnapshot();expect(wrapper.find(Availability).exists()).toBe(true);expect(wrapper.find(StockInfoLists).exists()).toBe(true);});it('should not render with display props set',function(){var wrapper=shallow(React.createElement(ItemDetails,_extends({},props,{display:display})));expect(wrapper).toBeEmptyRender();});});
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import React,{memo,useMemo}from'react';import PropTypes from'prop-types';import{SurroundPortals,DiscountBadge}from'@shopgate/engage/components';import{PRODUCT_ITEM_DISCOUNT}from'@shopgate/engage/category';import{makeStyles}from'@shopgate/engage/styles';var useStyles=makeStyles()({root:{minWidth:40}});/**
|
|
2
|
-
* The item discount component
|
|
3
|
-
* @param {Object} props The component props.
|
|
4
|
-
* @returns {JSX.Element|null}
|
|
5
|
-
*/var ItemDiscount=function ItemDiscount(_ref){var productId=_ref.productId,discount=_ref.discount;var _useStyles=useStyles(),classes=_useStyles.classes,cx=_useStyles.cx;var portalProps=useMemo(function(){return{productId:productId};},[productId]);if(!discount){return null;}return React.createElement("div",{className:cx(classes.root,'theme__product-grid__item__item-discount')},React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_DISCOUNT,portalProps:portalProps},React.createElement(DiscountBadge,{text:"-".concat(discount,"%")})));};ItemDiscount.defaultProps={discount:null};export default memo(ItemDiscount);
|
package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import React,{memo,useMemo}from'react';import PropTypes from'prop-types';import{useSelector}from'react-redux';import{SurroundPortals,FavoritesButton}from'@shopgate/engage/components';import{PRODUCT_ITEM_FAVORITES_BUTTON}from'@shopgate/engage/category';import{isRelativeProductOnList}from'@shopgate/engage/favorites';import{getLoadWishlistOnAppStartEnabled}from'@shopgate/engage/core';import{makeStyles}from'@shopgate/engage/styles';var useStyles=makeStyles()({root:{position:'absolute',top:0,right:16,left:'auto',transform:'translate3d(0, -50%, 0)'}});/**
|
|
2
|
-
* The item favorites button component.
|
|
3
|
-
* @param {Object} props The component props.
|
|
4
|
-
* @returns {JSX.Element}
|
|
5
|
-
*/var ItemFavoritesButton=function ItemFavoritesButton(_ref){var productId=_ref.productId;var _useStyles=useStyles(),classes=_useStyles.classes;var loadWishlistOnAppStartEnabled=useSelector(getLoadWishlistOnAppStartEnabled);var isOnWishlist=useSelector(function(state){return isRelativeProductOnList(state,{productId:productId});});var isFavorite=useMemo(function(){return!loadWishlistOnAppStartEnabled?false:isOnWishlist;},[isOnWishlist,loadWishlistOnAppStartEnabled]);var portalProps=useMemo(function(){return{productId:productId};},[productId]);return React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_FAVORITES_BUTTON,portalProps:portalProps},React.createElement("div",{className:classes.root,"data-test-id":"favorites"},React.createElement(FavoritesButton,{active:isFavorite,productId:productId,noShadow:true,removeWithRelatives:true})));};export default memo(ItemFavoritesButton);
|
package/product/components/ProductGrid/components/Item/components/ItemFavoritesButton/spec.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import React from'react';import{shallow}from'enzyme';import{combineReducers}from'redux';import{Provider}from'react-redux';import{createMockStore}from'@shopgate/pwa-common/store';import favorites from'@shopgate/pwa-common-commerce/favorites/reducers';import ItemFavoritesButton from"./index";jest.mock('@shopgate/engage/components');var store=createMockStore(combineReducers({favorites:favorites}));describe('<ItemFavoritesButton />',function(){it('should not render when its not a favorite',function(){var wrapper=shallow(React.createElement(Provider,{store:store},React.createElement(ItemFavoritesButton,{productId:"1234"})));expect(wrapper).toMatchSnapshot();});it('should render if its a favorite',function(){var wrapper=shallow(React.createElement(Provider,{store:store},React.createElement(ItemFavoritesButton,{productId:"1234",isFavorite:true})));expect(wrapper).toMatchSnapshot();});});
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import React,{useMemo,memo}from'react';import PropTypes from'prop-types';import{SurroundPortals}from'@shopgate/engage/components';import{PRODUCT_ITEM_IMAGE}from'@shopgate/engage/category/constants';import{getProductImageSettings,ProductImage}from'@shopgate/engage/product';var _getProductImageSetti=getProductImageSettings(),gridResolutions=_getProductImageSetti.ListImage;/**
|
|
2
|
-
* The item image component.
|
|
3
|
-
* @param {Object} props The component props.
|
|
4
|
-
* @returns {JSX.Element}
|
|
5
|
-
*/var ItemImage=function ItemImage(_ref){var productId=_ref.productId,name=_ref.name,imageUrl=_ref.imageUrl;var portalProps=useMemo(function(){return{productId:productId};},[productId]);return React.createElement(SurroundPortals,{portalName:PRODUCT_ITEM_IMAGE,portalProps:portalProps},React.createElement(ProductImage,{alt:name,src:imageUrl,resolutions:gridResolutions,itemProp:"image"}));};ItemImage.defaultProps={imageUrl:null,name:null};export default memo(ItemImage);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import React from'react';import{shallow}from'enzyme';import ItemImage from"./index";jest.mock('@shopgate/engage/components',function(){return{ProductImage:function ProductImage(){return null;}};});describe('<ItemImage />',function(){it('should render',function(){var wrapper=shallow(React.createElement(ItemImage,{productId:"1234",imageUrl:"http://www.google.com",name:"FooBar"}));expect(wrapper).toMatchSnapshot();});});
|