(function () {
if (typeof window.SwymStorefrontLayoutAPI === 'undefined') {
window.SwymStorefrontLayoutAPI = {};
}
if (typeof window.SwymStorefrontLayoutContext === 'undefined') {
window.SwymStorefrontLayoutContext = {};
}
if(typeof window.SwymStorefrontLayoutExtensions === 'undefined'){
window.SwymStorefrontLayoutExtensions = {};
}
function isShopifyStoreRTLEnabled() {
// Check dir attributes
const htmlDir = document.documentElement.getAttribute('dir');
const bodyDir = document.body.getAttribute('dir');
// Check computed CSS direction
const htmlCSSDir = getComputedStyle(document.documentElement).direction;
const bodyCSSDir = getComputedStyle(document.body).direction;
// Optional: check for common theme class
const hasRTLClass = document.documentElement.classList.contains('rtl') ||
document.body.classList.contains('rtl') ||
document.querySelector('.rtl, .is-rtl') !== null;
return (
htmlDir === 'rtl' ||
bodyDir === 'rtl' ||
htmlCSSDir === 'rtl' ||
bodyCSSDir === 'rtl' ||
hasRTLClass
);
}
const isRTL = isShopifyStoreRTLEnabled();
if (isRTL) {
document.body.classList.add('swym-ccui-rtl');
}
SwymStorefrontLayoutContext.ActionTypes = {
ManageListItem: 'ManageListItem',
ManageSflListItem: 'ManageSflListItem',
AddToCollection: 'AddToCollection',
CreateCollection: 'CreateCollection',
EditCollection: 'EditCollection',
SaveCollection: 'SaveCollection',
ShareSingleWishlist: 'ShareSingleWishlist'
}
SwymStorefrontLayoutContext.NotificationStatusTypes = {
Success: 'success',
Error: 'error',
Warning: 'Warning',
Info: 'info',
Neutral: 'neutral',
Toast: 'toast'
}
SwymStorefrontLayoutContext.NotificationActionTypes = {
AddedToWishlist: 'added-to-wishlist',
AddToCollection: 'add-to-collection',
AddedToCollection: 'added-to-collection',
AddedToCart: 'added-to-cart'
}
SwymStorefrontLayoutContext.StorefrontLayoutUrls = {
List: '#swym-list',
Collections: '#swym-collections',
CollectionList: '#swym-collection:'
}
SwymStorefrontLayoutContext.NotificationIconType = {
SuccessIcon: 'SuccessIcon',
RemoveIcon: 'RemoveIcon'
}
SwymStorefrontLayoutContext.LoaderViewType = {
WishlistListItem: 'wishlist-list-item',
CarouselListItem: 'carousel-list-item',
CollectionImages: 'collection-view-images',
SpinnerLoader: 'spinner-loader'
}
SwymStorefrontLayoutContext.StorefrontLayoutViewType = {
Wishlist: 'tabWishlist',
SaveForLater: 'tabSavedForLater'
}
SwymStorefrontLayoutContext.Tabs = [SwymStorefrontLayoutContext.StorefrontLayoutViewType.Wishlist]
SwymStorefrontLayoutContext.ListItemType = {
WishlistItem: 'WishlistItem',
CollectionItem: 'CollectionItem',
SaveForLaterItem: 'SaveForLaterItem'
}
SwymStorefrontLayoutContext.CommonAddtoWL = false;
SwymStorefrontLayoutContext.CommonRemovefromWL = false;
window._SwymAJAXCart = async function () {
try {
const cartComponent = document.querySelector('cart-notification') || document.querySelector('cart-drawer');
if (!cartComponent || typeof cartComponent.getSectionsToRender !== 'function') {
console.warn('[Cart Refresh] Cart component or getSectionsToRender is missing.');
const modalPopup = document.querySelector("modal-popup");
if(modalPopup && window.routes.cart) {
modalPopup.trigger("updateCart", {
callback: () => {
modalPopup.forwardEvent("openPopup", {
target: "CART",
url: window.routes.cart
});
}
});
return;
}
// Get current theme info
const currentThemeName = window?.Shopify?.theme?.schema_name?.trim();
const currentThemeId = window?.Shopify?.theme?.theme_store_id;
if (!currentThemeName) return false;
// Use preset API to get theme event configuration
window._swat.fetchThemePreset({
themeStoreId: currentThemeId,
schemaName: currentThemeName
}, (themeData) => {
if (themeData?.AJAXCartEvent?.[0]?.eventName) {
try {
// Get event details from preset API response
const event = themeData.AJAXCartEvent?.[0];
// Create event config object only with defined properties
const eventConfig = {};
if (event.bubbles !== undefined) {
eventConfig.bubbles = event.bubbles;
}
if (event.detail !== undefined) {
eventConfig.detail = event.detail;
}
// Create and dispatch custom event with only defined properties
const customEvent = new CustomEvent(event?.eventName, eventConfig);
// Dispatch event on appropriate target
const target = event.bubbles ? document.documentElement : document;
target.dispatchEvent(customEvent);
} catch (err) {
console.warn(`[Cart Refresh] Failed to dispatch event for theme ${currentThemeName}`, err);
}
}
});
return;
}
const sectionsToRender = cartComponent.getSectionsToRender();
const sectionIds = sectionsToRender.map(section => section.id).join(',');
if (!sectionIds) {
console.warn('[Cart Refresh] No section IDs found to render.');
return;
}
const [sectionRes, cartDataRes] = await Promise.all([
fetch(`/?sections=${sectionIds}`).then(res => res.ok ? res.json() : Promise.reject('Failed to fetch sections')),
fetch('/cart.js').then(res => res.ok ? res.json() : Promise.reject('Failed to fetch cart data'))
]);
const parser = new DOMParser();
// Update cart icon bubble
const cartIconBubble = document.getElementById('cart-icon-bubble');
const iconHtmlDoc = parser.parseFromString(sectionRes['cart-icon-bubble'], 'text/html');
const iconBubbleContent = iconHtmlDoc.getElementById('shopify-section-cart-icon-bubble')?.innerHTML;
if (cartIconBubble && iconBubbleContent) {
cartIconBubble.innerHTML = iconBubbleContent;
}
// Update cart drawer if it exists
const cartDrawer = document.querySelector('cart-drawer');
if (cartDrawer) {
const drawerHtmlDoc = parser.parseFromString(sectionRes['cart-drawer'], 'text/html');
const newDrawerContent = drawerHtmlDoc.querySelector('cart-drawer')?.innerHTML;
if (newDrawerContent !== undefined) {
cartDrawer.classList.toggle('is-empty', cartDataRes.item_count === 0);
cartDrawer.innerHTML = newDrawerContent;
const overlay = cartDrawer.querySelector('#CartDrawer-Overlay');
if (overlay) {
overlay.addEventListener('click', cartDrawer.close?.bind(cartDrawer));
}
}
}
} catch (error) {
console.error('[Cart Refresh] An error occurred:', error);
}
};
/**
* Checks if the current user has permission to edit the given wishlist.
* @param {Object} list - The wishlist to check.
* @returns {boolean} - Returns true if the user can edit the list, otherwise false.
*/
SwymStorefrontLayoutContext.checkUserCanEditList = (list) => {
if(!list){
window._swat?.utils.warn('list not exist to check list access');
return false;
}
if(list?.lty === 'sfl'){
let canEditList = SwymStorefrontLayoutContext?.sflList?.lid === list?.lid;
return canEditList;
}
let canEditList = SwymStorefrontLayoutContext?.lists?.some((userList)=> userList?.lid === list?.lid);
return canEditList;
}
/**
* Formats a given price based on the store's money formatting settings.
* @param {number} value - The price value to format.
* @returns {string} - The formatted price string.
*/
SwymStorefrontLayoutContext.FormatPrice = (value) => {
try {
if (window.SwymOverrideFormatMoneyFn) {
return window.SwymOverrideFormatMoneyFn(value);
}
if (window._swat.platform.formatMoney) {
if (
window._swat.platform.currentMoneyFormat &&
window._swat.platform.currentMoneyFormat()
) {
return window._swat.platform.formatMoney(
value * 100,
window._swat.platform.currentMoneyFormat()
);
}
}
} catch (err) {
window._swat?.utils.error("Error formatting price - " + value + err);
}
const currency = window._swat.currency;
return currency + window._swat.utils.padDecimal(value);
}
/**
* Retrieves the selected variant from a given item based on the provided variant ID.
*
* @param {Object} item - The item containing product data and variants.
* @param {string | number} variantId - The ID of the variant to find.
* @returns {Object | null} - The matching variant object if found, otherwise null.
*/
SwymStorefrontLayoutContext.getSelectedVariant = (item, variantId) => {
return variantId? item?.productData?.variants?.find((variant) => variant?.id === variantId) || null:null;
}
/**
* Calculates the difference in hours between the current time and a given date-time string.
* @param {number} hours - The threshold hours to compare.
* @param {string} dateTimeString - The stored date-time string.
* @returns {boolean} - Returns true if the time difference exceeds the given hours, otherwise false.
*/
SwymStorefrontLayoutExtensions.calcDifferenceInHours = (hours, dateTimeString) => {
try {
if (!dateTimeString) {
window._swat?.utils.warn("[WARNING] Date time string empty");
return;
}
const storedDateTime = new Date(dateTimeString?.trim());
const currentDateTime = new Date();
const differenceInMs = Math.abs(currentDateTime - storedDateTime);
const differenceInHours = differenceInMs / (1000 * 60 * 60);
return differenceInHours > hours;
} catch (error) {
window._swat?.utils.warn("[Error/Warning] while performing health check", error);
return false;
}
}
/**
* Checks if a given container has a scrollbar and applies/removes a CSS class accordingly.
* @param {HTMLElement} container - The container element to check.
*/
SwymStorefrontLayoutExtensions.checkContainerScrollbar = (container) => {
try{
if(!container){
window._swat?.utils.warn("container not available for scrollbar check");
return;
}
if (container.scrollHeight > container.clientHeight) {
container.classList.add("swym-storefront-layout-container-has-scroll");
} else {
container.classList.remove("swym-storefront-layout-container-has-scroll");
}
}catch(error){
window._swat?.utils.warn("invalid container for scrollbar check");
}
}
SwymStorefrontLayoutExtensions.refreshWishList = () => {
try {
SwymStorefrontLayoutAPI?.SwymWLAsyncApis?.updateList();
} catch (error) {
window._swat?.utils.error('Failed to fetch wishlist', error);
}
}
SwymStorefrontLayoutExtensions.refreshSFLList = () => {
try {
SwymStorefrontLayoutAPI?.SwymSFLAsyncApis?.updateSflList();
} catch (error) {
window._swat?.utils.error('Failed to fetch sfl list', error);
}
}
/**
* Defines action codes for various storefront layout events.
*/
SwymStorefrontLayoutExtensions.InstrumentActionCodes = {
StorefrontLayoutInitialized: 701,
StorefrontLayoutOpened: 702,
StorefrontLayoutClosed: 703,
StorefrontLayoutUserLogIn: 704,
StorefrontLayoutCollectionRendered: 705,
StorefrontLayoutWishlistItemsRendered: 706,
StorefrontLayoutVariantChanged: 707,
StorefrontLayoutItemAddedToCart: 708,
StorefrontLayoutItemAddedToList: 709,
StorefrontLayoutItemRemovedFromList: 710,
StorefrontLayoutCollectionCreated: 711,
StorefrontLayoutCollectionOpened: 712,
StorefrontLayoutCollectionRenamed: 713,
StorefrontLayoutCollectionDeleted: 714,
StorefrontLayoutCollectionGridViewOpened: 715,
StorefrontLayoutSFLInitialized: 716,
StorefrontLayoutSFLItemsRendered: 717,
StorefrontLayoutSFLItemAddedToList: 718,
StorefrontLayoutSFLItemRemovedFromList: 719,
StorefrontLayoutSFLItemMovedToCart: 720,
StorefrontLayoutPageRendered: 721,
StorefrontLayoutModalRendered: 722,
StorefrontLayoutSideDrawerRendered: 723
};
/**
* Defines UTM terms for tracking user engagement and interactions.
*/
SwymStorefrontLayoutExtensions.InstrumentUtmTerms = {
StorefrontLayoutUiEngagement: "storefront_layout_ui_engagement",
StorefrontLayoutCollectionInteractions: "storefront_layout_collection_interactions",
StorefrontLayoutItemInteractions: "storefront_layout_item_interactions",
StorefrontLayoutCartConversion: "storefront_layout_cart_conversion"
};
/**
* SwymWishlistCore Component
*
* This component serves as the base class for Swym Wishlist Storefront Layout,
* providing the core functionality shared across different layout implementations:
* - Drawer
* - Page Section
* - Modal
*
* Key Responsibilities:
* - Initializes the UI and sets up event listeners for wishlist interactions.
* - Handles fetching and rendering of wishlist items and collections.
* - Monitors hash changes to update the UI accordingly.
* - Integrates with Swym's API for wishlist actions and notifications.
* - Provides a structured foundation for extending different storefront layout types.
*
* The component can be extended by specific layout implementations such as:
* - `SwymStorefrontLayoutAsDrawer`
* - `SwymStorefrontLayoutAsPageSection`
* - `SwymStorefrontLayoutAsModal`
*/
class SwymWishlistCore extends HTMLElement {
constructor() {
super();
this.elements = {};
this.initUi();
}
initUi(){
this.setAttribute('id', 'swym-storefront-layout');
window.addEventListener('hashchange', ()=>{
this.checkForSwymDrawerHash();
});
document.addEventListener(SwymStorefrontLayoutContext?.CustomEvents?.LayoutInitialized, () => {
SwymStorefrontLayoutContext?.swat.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutInitialized, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
this.checkForSwymDrawerHash();
this.initElement();
SwymStorefrontLayoutContext?.swat.evtLayer.addEventListener(SwymStorefrontLayoutContext?.swat.JSEvents.StringsLoaded, (event) => {
this.loadStrings();
});
this.attachSwymEventListeners(SwymStorefrontLayoutContext.swat);
this.instrumentLayoutType();
});
document.addEventListener(SwymStorefrontLayoutContext?.CustomEvents?.WishlistFetched, () => {
this.checkForSwymDrawerHash();
})
}
instrumentLayoutType(){
let StorefrontLayoutType = SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutType;
if(StorefrontLayoutType === 'as-drawer'){
SwymStorefrontLayoutContext?.swat.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutSideDrawerRendered, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
}else if(StorefrontLayoutType === 'as-modal'){
SwymStorefrontLayoutContext?.swat.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutModalRendered, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
}else if(StorefrontLayoutType === 'as-section'){
SwymStorefrontLayoutContext?.swat.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutPageRendered, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
}
}
reRenderStorefrontLayoutUI() {
this.reRenderUI();
this.initElement();
}
initElement(){
SwymStorefrontLayoutExtensions.SwymStorefrontLayout = document.querySelector('swym-storefront-layout #swym-storefront-layout');
SwymStorefrontLayoutExtensions.SwymStorefrontLayoutActions = document.querySelector('#swym-storefront-layout-actions') || document.querySelector('#swym-storefront-layout-actions-target-page');
SwymStorefrontLayoutExtensions.SwymStorefrontLayoutActionTooltip = document.querySelector('#swym-storefront-layout-action-tooltip') || document.querySelector('#swym-storefront-layout-action-tooltip-target-page');
SwymStorefrontLayoutExtensions.Notification = document.querySelector('swym-storefront-layout-notification');
SwymStorefrontLayoutExtensions.collectionsListComponent = document.querySelector('swym-storefront-layout-collection-list');
}
loadStrings() {
try {
const RetailerStrings = window._swat?.retailerSettings?.Strings || {};
const {
ThemeAppStorefrontLayoutTitle,
ThemeAppStorefrontLayoutAddToCartCTA,
ThemeAppStorefrontLayoutAddedToCartCTA,
ThemeAppStorefrontLayoutAddingToCartCTA,
ThemeAppStorefrontLayoutSoldoutCTA,
ThemeAppStorefrontLayoutViewCartCTA,
ThemeAppStorefrontLayoutMoveToCartCTA,
ThemeAppStorefrontLayoutMoveingToCartCTA,
ThemeAppStorefrontLayoutRemoveSFLItemCTA,
ThemeAppStorefrontLayoutLoginHeading,
ThemeAppStorefrontLayoutLoginMessage,
ThemeAppStorefrontLayoutLoginButtonCTA,
ThemeAppStorefrontLayoutLoggedUserWelcomeMessage,
ThemeAppStorefrontLayoutWishlistTitle,
ThemeAppStorefrontLayoutWishlistInfo,
ThemeAppStorefrontLayoutEmptyWishlistTitle,
ThemeAppStorefrontLayoutEmptyWishlistDescription,
ThemeAppStorefrontLayoutCollectionsTitle,
ThemeAppStorefrontLayoutEmptyCarouselCollectionsDescription,
ThemeAppStorefrontLayoutEmptyCollectionsTitle,
ThemeAppStorefrontLayoutEmptyCollectionsDescription,
ThemeAppStorefrontLayoutAddToCollectionsTitle,
ThemeAppStorefrontLayoutAddToCollectionCTA,
ThemeAppStorefrontLayoutCreateCollectionCTA,
ThemeAppStorefrontLayoutSaveNewCollectionCTA,
ThemeAppStorefrontLayoutRemoveItemCTA,
ThemeAppStorefrontLayoutRenameCollectionCTA,
ThemeAppStorefrontLayoutDeleteCollectionCTA,
ThemeAppStorefrontLayoutShareCollectionCTA,
ThemeAppStorefrontLayoutSaveCollectionCTA,
ThemeAppStorefrontLayoutEditCollectionCTA,
ThemeAppStorefrontLayoutShareCollectionTitle,
ThemeAppStorefrontLayoutShareCollectionMessage,
ThemeAppStorefrontLayoutSharedCollectionMessage,
ThemeAppStorefrontLayoutUpdateCollectionTitle,
ThemeAppStorefrontLayoutErrorMessageListNameRequired,
ThemeAppStorefrontLayoutErrorMessageListNameRequired3Char,
ThemeAppStorefrontLayoutErrorMessageListNameAlreadyExist,
ThemeAppStorefrontLayoutNotificationMessageItemSaved,
ThemeAppStorefrontLayoutNotificationMessageItemRemoved,
ThemeAppStorefrontLayoutNotificationMessageAddedToCart,
ThemeAppStorefrontLayoutNotificationMessageAddedToCollection,
ThemeAppStorefrontLayoutNotificationMessageCollectionSaved,
ThemeAppStorefrontLayoutNotificationMessageCollectionDeleted,
ThemeAppStorefrontLayoutNotificationMessageCollectionUpdated,
ThemeAppStorefrontLayoutNotificationMessageCollectionUnavailable,
ThemeAppStorefrontLayoutNotificationMessageSFLItemSaved,
ThemeAppStorefrontLayoutNotificationMessageSFLItemRemoved,
ThemeAppStorefrontLayoutNotificationMessageMovedToCart,
ThemeAppStorefrontLayoutNotificationActionAddToCollection,
ThemeAppStorefrontLayoutNotificationActionView,
ThemeAppStorefrontLayoutNotificationActionViewCollection,
ThemeAppStorefrontLayoutNotificationActionGoToCart,
ThemeAppStorefrontLayoutTextItem,
ThemeAppStorefrontLayoutTextItems,
ThemeAppStorefrontLayoutTabWishlist,
ThemeAppStorefrontLayoutTabSavedForLater,
ThemeAppStorefrontLayoutSaveForLaterTitle,
ThemeAppStorefrontLayoutEmptySavedForLaterTitle,
ThemeAppStorefrontLayoutEmptySavedForLaterDescription,
VariantSelectorBtnText
} = RetailerStrings;
SwymStorefrontLayoutContext.Strings = {
...SwymStorefrontLayoutContext?.Strings,
...(ThemeAppStorefrontLayoutTitle ? { 'title': ThemeAppStorefrontLayoutTitle } : {}),
...(VariantSelectorBtnText ? { 'VariantSelectorBtnText': VariantSelectorBtnText } : {}),
...(ThemeAppStorefrontLayoutAddToCartCTA ? { 'addToCart': ThemeAppStorefrontLayoutAddToCartCTA } : {}),
...(ThemeAppStorefrontLayoutAddedToCartCTA ? { 'addedToCart': ThemeAppStorefrontLayoutAddedToCartCTA } : {}),
...(ThemeAppStorefrontLayoutAddingToCartCTA ? { 'addingToCart': ThemeAppStorefrontLayoutAddingToCartCTA } : {}),
...(ThemeAppStorefrontLayoutSoldoutCTA ? { 'soldOut': ThemeAppStorefrontLayoutSoldoutCTA } : {}),
...(ThemeAppStorefrontLayoutViewCartCTA ? { 'viewCartCta': ThemeAppStorefrontLayoutViewCartCTA } : {}),
...(ThemeAppStorefrontLayoutMoveToCartCTA ? { 'moveToCartCta': ThemeAppStorefrontLayoutMoveToCartCTA } : {}),
...(ThemeAppStorefrontLayoutMoveingToCartCTA ? { 'movingToCartCta': ThemeAppStorefrontLayoutMoveingToCartCTA } : {}),
...(ThemeAppStorefrontLayoutRemoveSFLItemCTA ? { 'removeSflItemCta': ThemeAppStorefrontLayoutRemoveSFLItemCTA } : {}),
...(ThemeAppStorefrontLayoutLoginHeading ? { 'loginHeading': ThemeAppStorefrontLayoutLoginHeading } : {}),
...(ThemeAppStorefrontLayoutLoginMessage ? { 'loginText': ThemeAppStorefrontLayoutLoginMessage } : {}),
...(ThemeAppStorefrontLayoutLoginButtonCTA ? { 'loginButtonText': ThemeAppStorefrontLayoutLoginButtonCTA } : {}),
...(ThemeAppStorefrontLayoutLoggedUserWelcomeMessage ? { 'loggedUserWelcomeMessage': ThemeAppStorefrontLayoutLoggedUserWelcomeMessage } : {}),
...(ThemeAppStorefrontLayoutWishlistTitle ? { 'wishlistTitle': ThemeAppStorefrontLayoutWishlistTitle } : {}),
...(ThemeAppStorefrontLayoutWishlistInfo ? { 'wishlistInfo': ThemeAppStorefrontLayoutWishlistInfo } : {}),
...(ThemeAppStorefrontLayoutEmptyWishlistTitle ? { 'emptyWishlistTitle': ThemeAppStorefrontLayoutEmptyWishlistTitle } : {}),
...(ThemeAppStorefrontLayoutEmptyWishlistDescription ? { 'emptyWishlistDescription': ThemeAppStorefrontLayoutEmptyWishlistDescription } : {}),
...(ThemeAppStorefrontLayoutCollectionsTitle ? { 'collectionTitle': ThemeAppStorefrontLayoutCollectionsTitle } : {}),
...(ThemeAppStorefrontLayoutEmptyCarouselCollectionsDescription ? { 'emptyCarouselCollectionText': ThemeAppStorefrontLayoutEmptyCarouselCollectionsDescription } : {}),
...(ThemeAppStorefrontLayoutEmptyCollectionsTitle ? { 'emptyCollectionText': ThemeAppStorefrontLayoutEmptyCollectionsTitle } : {}),
...(ThemeAppStorefrontLayoutEmptyCollectionsDescription ? { 'emptyCollectionDescription': ThemeAppStorefrontLayoutEmptyCollectionsDescription } : {}),
...(ThemeAppStorefrontLayoutAddToCollectionsTitle ? { 'addToCollectionTitle': ThemeAppStorefrontLayoutAddToCollectionsTitle } : {}),
...(ThemeAppStorefrontLayoutAddToCollectionCTA ? { 'addToCollectionCta': ThemeAppStorefrontLayoutAddToCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutCreateCollectionCTA ? { 'createCollectionCta': ThemeAppStorefrontLayoutCreateCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutSaveNewCollectionCTA ? { 'saveNewCollectionCta': ThemeAppStorefrontLayoutSaveNewCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutRemoveItemCTA ? { 'removeItemCta': ThemeAppStorefrontLayoutRemoveItemCTA } : {}),
...(ThemeAppStorefrontLayoutRenameCollectionCTA ? { 'renameCollectionCta': ThemeAppStorefrontLayoutRenameCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutDeleteCollectionCTA ? { 'deleteCollectionCta': ThemeAppStorefrontLayoutDeleteCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutShareCollectionCTA ? { 'shareCollectionCta': ThemeAppStorefrontLayoutShareCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutSaveCollectionCTA ? { 'saveCollectionCta': ThemeAppStorefrontLayoutSaveCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutEditCollectionCTA ? { 'editCollectionCta': ThemeAppStorefrontLayoutEditCollectionCTA } : {}),
...(ThemeAppStorefrontLayoutShareCollectionTitle ? { 'shareCollectionTitle': ThemeAppStorefrontLayoutShareCollectionTitle } : {}),
...(ThemeAppStorefrontLayoutShareCollectionMessage ? { 'shareCollectionMessage': ThemeAppStorefrontLayoutShareCollectionMessage } : {}),
...(ThemeAppStorefrontLayoutSharedCollectionMessage ? { 'sharedCollectionMessage': ThemeAppStorefrontLayoutSharedCollectionMessage } : {}),
...(ThemeAppStorefrontLayoutUpdateCollectionTitle ? { 'updateCollectionTitle': ThemeAppStorefrontLayoutUpdateCollectionTitle } : {}),
...(ThemeAppStorefrontLayoutErrorMessageListNameRequired ? { 'errorMessageListNameRequired': ThemeAppStorefrontLayoutErrorMessageListNameRequired } : {}),
...(ThemeAppStorefrontLayoutErrorMessageListNameRequired3Char ? { 'errorMessageListNameRequire3Char': ThemeAppStorefrontLayoutErrorMessageListNameRequired3Char } : {}),
...(ThemeAppStorefrontLayoutErrorMessageListNameAlreadyExist ? { 'errorMessageListNameAlreadyExist': ThemeAppStorefrontLayoutErrorMessageListNameAlreadyExist } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageItemSaved ? { 'notificationMessageItemSaved': ThemeAppStorefrontLayoutNotificationMessageItemSaved } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageItemRemoved ? { 'notificationMessageItemRemoved': ThemeAppStorefrontLayoutNotificationMessageItemRemoved } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageAddedToCart ? { 'notificationMessageAddedToCart': ThemeAppStorefrontLayoutNotificationMessageAddedToCart } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageAddedToCollection ? { 'notificationMessageAddedToCollection': ThemeAppStorefrontLayoutNotificationMessageAddedToCollection } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageCollectionSaved ? { 'notificationMessageCollectionSaved': ThemeAppStorefrontLayoutNotificationMessageCollectionSaved } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageCollectionDeleted ? { 'notificationMessageCollectionDeleted': ThemeAppStorefrontLayoutNotificationMessageCollectionDeleted } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageCollectionUpdated ? { 'notificationMessageCollectionUpdated': ThemeAppStorefrontLayoutNotificationMessageCollectionUpdated } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageCollectionUnavailable ? { 'notificationMessageCollectionUnavailable': ThemeAppStorefrontLayoutNotificationMessageCollectionUnavailable } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageSFLItemSaved ? { 'notificationMessageSFLItemSaved': ThemeAppStorefrontLayoutNotificationMessageSFLItemSaved } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageSFLItemRemoved ? { 'notificationMessageSFLItemRemoved': ThemeAppStorefrontLayoutNotificationMessageSFLItemRemoved } : {}),
...(ThemeAppStorefrontLayoutNotificationMessageMovedToCart ? { 'notificationMessageMovedToCart': ThemeAppStorefrontLayoutNotificationMessageMovedToCart } : {}),
...(ThemeAppStorefrontLayoutNotificationActionAddToCollection ? { 'notificationActionAddToCollection': ThemeAppStorefrontLayoutNotificationActionAddToCollection } : {}),
...(ThemeAppStorefrontLayoutNotificationActionView ? { 'notificationActionView': ThemeAppStorefrontLayoutNotificationActionView } : {}),
...(ThemeAppStorefrontLayoutNotificationActionViewCollection ? { 'notificationActionViewCollection': ThemeAppStorefrontLayoutNotificationActionViewCollection } : {}),
...(ThemeAppStorefrontLayoutNotificationActionGoToCart ? { 'notificationActionGoToCart': ThemeAppStorefrontLayoutNotificationActionGoToCart } : {}),
...(ThemeAppStorefrontLayoutTextItem ? { 'item': ThemeAppStorefrontLayoutTextItem } : {}),
...(ThemeAppStorefrontLayoutTextItems ? { 'items': ThemeAppStorefrontLayoutTextItems } : {}),
...(ThemeAppStorefrontLayoutTabWishlist ? { 'tabWishlist': ThemeAppStorefrontLayoutTabWishlist } : {}),
...(ThemeAppStorefrontLayoutTabSavedForLater ? { 'tabSavedForLater': ThemeAppStorefrontLayoutTabSavedForLater } : {}),
...(ThemeAppStorefrontLayoutSaveForLaterTitle ? { 'savedForLaterTitle': ThemeAppStorefrontLayoutSaveForLaterTitle } : {}),
...(ThemeAppStorefrontLayoutEmptySavedForLaterTitle ? { 'emptySavedForLaterTitle': ThemeAppStorefrontLayoutEmptySavedForLaterTitle } : {}),
...(ThemeAppStorefrontLayoutEmptySavedForLaterDescription ? { 'emptySavedForLaterDescription': ThemeAppStorefrontLayoutEmptySavedForLaterDescription } : {}),
}
this.reRenderStorefrontLayoutUI();
} catch (error) {
window._swat?.utils.error(error);
}
}
async checkForSwymDrawerHash() {
const { StorefrontLayoutType, StorefrontLayoutAsSectionPageURL } = SwymStorefrontLayoutContext?.Settings;
const currentHash = window.location.hash;
if(!SwymStorefrontLayoutExtensions.SwymStorefrontLayout){
SwymStorefrontLayoutExtensions.SwymStorefrontLayout = document.querySelector('swym-storefront-layout #swym-storefront-layout');
}
if(!currentHash && SwymStorefrontLayoutExtensions.SwymStorefrontLayout?.isOpen){
SwymStorefrontLayoutExtensions.SwymStorefrontLayout?.close();
return;
}
const openWishlistPage = () => {
if (StorefrontLayoutType === 'as-drawer' || StorefrontLayoutType === 'as-modal') {
SwymStorefrontLayoutExtensions?.SwymStorefrontLayout?.open();
} else if (StorefrontLayoutType === 'as-section' && window.location.pathname !== StorefrontLayoutAsSectionPageURL) {
const locale = window.Shopify.routes.root
const formattedLocale = locale === '/' ? '' : locale.replace(/\/$/, '')
window.location = `${window.location.origin}${formattedLocale}${StorefrontLayoutAsSectionPageURL}`;
history.replaceState(null, '', window.location.pathname + window.location.search);
}
};
if (currentHash === SwymStorefrontLayoutContext?.StorefrontLayoutUrls?.List) {
SwymStorefrontLayoutExtensions?.collectionsListComponent?.closeCollectinListView();
openWishlistPage();
} else if (currentHash.startsWith(SwymStorefrontLayoutContext?.StorefrontLayoutUrls?.CollectionList)) {
const collectionId = currentHash.slice(SwymStorefrontLayoutContext?.StorefrontLayoutUrls?.CollectionList.length);
if (collectionId && SwymStorefrontLayoutContext?.collections) {
const selectedCollection = SwymStorefrontLayoutContext?.collections?.find(collection => collection.lid === collectionId);
if (selectedCollection) {
SwymStorefrontLayoutExtensions?.collectionsListComponent?.setData({
list: selectedCollection,
collections: SwymStorefrontLayoutContext?.collections
});
SwymStorefrontLayoutExtensions?.collectionsListComponent?.openCollectionListView();
} else {
try{
const sharedListDetails = await SwymStorefrontLayoutAPI?.SwymWLAsyncApis?.fetchListDetails(collectionId);
if(sharedListDetails?.list){
let [list] = await SwymStorefrontLayoutAPI?.SwymWLAsyncApis?.fetchProductDataForLists([sharedListDetails.list], true) || [];
if(list){
SwymStorefrontLayoutExtensions?.collectionsListComponent?.setData({
list,
collections: SwymStorefrontLayoutContext?.collections
});
SwymStorefrontLayoutExtensions?.collectionsListComponent?.openCollectionListView();
}else{
throw 'Failed to get product data for shared list';
}
}else{
throw 'Collection Not Available';
}
}catch(e){
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
message: SwymStorefrontLayoutContext?.Strings?.notificationMessageCollectionUnavailable,
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Error,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration
});
window._swat?.utils.error(`Collection detail not found for ID: ${collectionId}. It may have been deleted or is unavailable.`,e);
}
}
openWishlistPage();
}
}
}
/**
* Attaches event listeners to Swym's event layer for handling various storefront layout interactions.
*
* Key Features:
* - Refreshes the wishlist and save-for-later (SFL) lists when customer information is updated.
* - Handles events for adding and removing items from the wishlist and SFL.
* - Displays notifications for user actions such as adding to wishlist, removing items, or moving items to the cart.
* - Tracks user interactions using Swym's instrumentation for analytics.
* - Supports multi-list and collection features based on retailer settings.
*
* Events Handled:
* - `customerInfoRefreshed`: Refreshes wishlist and SFL lists.
* - `addedToWishlist`: Updates the wishlist and displays a notification when an item is added.
* - `removedFromWishlist`: Updates the wishlist and displays a notification when an item is removed.
* - `addedToSFL`: Updates the SFL list and displays a notification when an item is added.
* - `removedFromSFL`: Updates the SFL list and displays a notification when an item is removed.
* - `movedToCartFromSFL`: Refreshes the SFL list when an item is moved to the cart.
*
* Dependencies:
* - SwymStorefrontLayoutExtensions: Provides methods for refreshing lists and managing notifications.
* - SwymStorefrontLayoutContext: Provides context for settings, strings, and instrumentation codes.
* - Swym's event layer (`swat.evtLayer`): Listens for and triggers events.
*/
attachSwymEventListeners(swat) {
swat?.evtLayer?.addEventListener(swat?.JSEvents?.customerInfoRefreshed, ()=>{
SwymStorefrontLayoutExtensions?.refreshWishList();
if(window._swat?.retailerSettings?.SFL?.SFLFeatureEnabled){
SwymStorefrontLayoutExtensions?.refreshSFLList();
}
})
//Wishlist Events
swat?.evtLayer?.addEventListener(swat?.JSEvents?.addedToWishlist, (event) => {
const isMultiListEnabled = swat.retailerSettings?.Wishlist?.EnableCollections;
SwymStorefrontLayoutExtensions?.refreshWishList();
let image = event?.detail?.d?.iu || null;
let { epi, empi } = event?.detail?.d || {};
let product = event?.detail.d;
swat?.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutItemAddedToList, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutItemInteractions, epi, empi });
if(SwymStorefrontLayoutContext?.swat?.ui?.uiRef?.settings?.UI?.WishlistShowNotification && !SwymStorefrontLayoutContext.CommonAddtoWL){
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
message: SwymStorefrontLayoutContext?.Strings?.notificationMessageItemSaved,
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Neutral,
actionType: SwymStorefrontLayoutContext?.NotificationActionTypes.AddedToWishlist,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
product,
image
},{
showImage: true,
showProgress: true
});
setTimeout(()=>{
// FIXME - remove repetative code once testing is done
const isOldControlCentre = !('multiple-wishlist' in (window?.SwymEnabledCommonFeatures || {}));
// Determine the boolean condition based on whether it's the old or new control centre
const shouldAddToCollection = isOldControlCentre
? SwymStorefrontLayoutContext?.Settings?.EnableStorefrontLayoutCollection // For old control centre, use this setting
: window?.SwymEnabledCommonFeatures?.['multiple-wishlist']; // For new control centre, use this feature flag
if(SwymStorefrontLayoutExtensions?.Notification?.notificationData?.actionType === SwymStorefrontLayoutContext?.NotificationActionTypes?.AddedToWishlist){
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Neutral,
actionType: SwymStorefrontLayoutContext?.NotificationActionTypes.AddedToWishlist,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
product,
image,
action: {
label: shouldAddToCollection ? SwymStorefrontLayoutContext?.Strings?.notificationActionAddToCollection: SwymStorefrontLayoutContext?.Strings?.notificationActionView,
onClick: () => {
if(shouldAddToCollection){
SwymStorefrontLayoutExtensions?.SwymStorefrontLayoutPageActions?.setData({
listId: SwymStorefrontLayoutContext?.DefaultList?.lid,
list: SwymStorefrontLayoutContext?.DefaultList,
item: product,
collections: SwymStorefrontLayoutContext?.collections,
actionType: SwymStorefrontLayoutContext?.ActionTypes.AddToCollection
});
SwymStorefrontLayoutExtensions?.SwymStorefrontLayoutPageActions?.openDrawer();
}else{
window.location.hash = SwymStorefrontLayoutContext?.StorefrontLayoutUrls?.List;
}
}
}
},{
showImage: true,
showActionButton: true,
showTitle: true
});
}
},3000);
}
if(SwymStorefrontLayoutContext.CommonAddtoWL && !SwymStorefrontLayoutContext.CommonRemovefromWL) {
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
message: SwymStorefrontLayoutContext?.Strings?.notificationMessageItemSaved,
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Neutral,
actionType: SwymStorefrontLayoutContext?.NotificationActionTypes.AddedToWishlist,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
product,
image
},{
showImage: true,
showProgress: true
});
SwymStorefrontLayoutContext.CommonAddtoWL = false
setTimeout(() => {
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Neutral,
actionType: SwymStorefrontLayoutContext?.NotificationActionTypes.AddedToWishlist,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
product,
image,
action: {
label: SwymStorefrontLayoutContext?.Strings?.notificationActionView,
onClick: () => {
_swat.ui.open();
}
}
},{
showImage: true,
showActionButton: true,
showTitle: true
});
}, 3000)
}
});
swat?.evtLayer?.addEventListener(swat?.JSEvents?.removedFromWishlist, (event) => {
let image = event?.detail?.d?.iu || null;
let { epi, empi } = event?.detail?.d || {};
const product = event?.detail.d;
if( epi && empi){
SwymStorefrontLayoutExtensions?.refreshWishList();
swat?.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutItemRemovedFromList, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutItemInteractions, epi, empi });
}
if((SwymStorefrontLayoutContext.CommonRemovefromWL && SwymStorefrontLayoutContext.CommonAddtoWL) || SwymStorefrontLayoutContext.CommonRemovefromWL) {
if(SwymStorefrontLayoutContext.CommonRemovefromWL && !SwymStorefrontLayoutContext.CommonAddtoWL) {
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
message: SwymStorefrontLayoutContext?.Strings?.notificationMessageItemRemoved,
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Toast,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
image
});
SwymStorefrontLayoutContext.CommonRemovefromWL = false;
setTimeout(() => {
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Neutral,
actionType: SwymStorefrontLayoutContext?.NotificationActionTypes.AddedToWishlist,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
product,
image,
action: {
label: SwymStorefrontLayoutContext?.Strings?.notificationActionView,
onClick: () => {
_swat.ui.open();
}
}
},{
showImage: true,
showActionButton: true,
showTitle: true
});
}, 3000)
}
return
}
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
message: SwymStorefrontLayoutContext?.Strings?.notificationMessageItemRemoved,
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Toast,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
image
});
});
//SFL Events
if(window._swat?.retailerSettings?.SFL?.SFLFeatureEnabled){
swat.evtLayer.addEventListener(swat.JSEvents.addedToSFL, (event) => {
let image = event?.detail?.d?.iu || null;
let title = event?.detail?.d?.dt || null;
let { epi, empi } = event?.detail?.d || {};
window._swat.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutSFLItemAddedToList, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutItemInteractions, epi, empi });
SwymStorefrontLayoutExtensions?.refreshSFLList();
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
message: SwymStorefrontLayoutContext?.Strings?.notificationMessageSFLItemSaved,
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Neutral,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
image,
title
},{
showProgress: true,
showTitle: true
});
});
swat.evtLayer.addEventListener(swat.JSEvents.removedFromSFL, (event) => {
let image = event?.detail?.d?.iu || null;
let title = event?.detail?.d?.dt || null;
let { epi, empi } = event?.detail?.d || {};
window._swat.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutSFLItemRemovedFromList, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutItemInteractions, epi, empi });
SwymStorefrontLayoutExtensions?.refreshSFLList();
SwymStorefrontLayoutExtensions?.Notification?.setMessage({
message: SwymStorefrontLayoutContext?.Strings?.notificationMessageSFLItemRemoved,
status: SwymStorefrontLayoutContext?.NotificationStatusTypes?.Neutral,
duration: SwymStorefrontLayoutContext?.Settings?.StorefrontLayoutNotificationDuration,
image,
title
},{
showProgress: true,
showTitle: true
});
});
swat.evtLayer.addEventListener(swat.JSEvents.movedToCartFromSFL, (event) => {
swat.utils.debounce(()=>{
SwymStorefrontLayoutExtensions?.refreshSFLList();
}, 1000)();
});
}
}
}
/**
* SwymStorefrontLayoutAsModal
*
* This class extends SwymWishlistCore to render a modal-based storefront layout for the Swym wishlist.
* It manages UI rendering, event listeners, and open/close interactions.
*
* Features:
* - Displays a modal layout for wishlist functionality.
* - Supports collection carousel based on SwymStorefrontLayoutContext settings.
* - Provides a close button and backdrop click handling to close the modal.
* - Tracks UI engagement using Swym's instrumentation.
*
* Methods:
* - renderUI(): Generates the modal's HTML structure.
* - initUIElement(): Initializes UI elements and event listeners.
* - attachDrawerEventListner(): Binds click events to close the modal.
* - open(): Opens the modal and updates the UI state.
* - close(): Closes the modal, removes body scroll lock, and updates history state.
* - reRenderUI(): Re-renders the UI while preserving the open state.
*
* Usage:
*
*/
class SwymStorefrontLayoutAsModal extends SwymWishlistCore {
constructor() {
super();
this.renderUI();
}
renderUI() {
this.innerHTML = `
`
this.initUIElement();
}
initUIElement() {
this.elements = {
drawer: this.querySelector('.swym-storefront-layout-drawer'),
drawerCloseButton: this.querySelector('#swym-storefront-layout-close-drawer-button'),
drawerbackdrop: this.querySelector('.swym-storefront-layout-backdrop'),
collectionList: this.querySelector('#swym-storefront-layout-collection-list'),
}
this.attachDrawerEventListner();
}
attachDrawerEventListner() {
this.elements.drawerCloseButton.addEventListener('click', this.close.bind(this));
this.elements.drawerbackdrop.addEventListener('click', this.close.bind(this));
}
open() {
this.isOpen = true;
if (this.elements && this.elements.drawer) {
this.elements.drawer.classList.remove('swym-storefront-layout-hide-view');
document.body.classList.add('swym-storefront-layout-body-no-scroll');
window._swat?.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutOpened, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
}
}
close() {
this.isOpen = false;
if (this.elements && this.elements.drawer) {
this.elements.drawer.classList.add('swym-storefront-layout-hide-view');
document.body.classList.remove('swym-storefront-layout-body-no-scroll');
history.replaceState(null, '', window.location.pathname + window.location.search);
window._swat?.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutClosed, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
}
}
reRenderUI() {
this.renderUI();
if (this.isOpen) {
this.open();
}
}
}
/**
* SwymStorefrontLayoutAsSection
*
* This class extends SwymWishlistCore to render a storefront wishlist layout as a section within a specified container.
* It dynamically injects the wishlist UI into the provided container element.
*
* Features:
* - Renders the wishlist section inside a container specified by the `container-id` attribute.
* - Supports collection carousel based on SwymStorefrontLayoutContext settings.
* - Displays wishlist items and user login UI.
* - Handles rendering errors gracefully and logs warnings if an invalid container ID is provided.
*
* Methods:
* - renderUI(): Generates the section-based wishlist UI and injects it into the specified container.
* - reRenderUI(): Re-renders the UI to reflect any updates.
*
* Usage:
*
*/
class SwymStorefrontLayoutAsSection extends SwymWishlistCore {
constructor() {
super();
this.containerId = this.getAttribute('container-id');
this.renderUI();
}
renderUI() {
let { StorefrontLayoutType } = SwymStorefrontLayoutContext?.Settings;
if(StorefrontLayoutType === 'as-section'){
this.listContainerToRender = null;
try {
this.listContainerToRender = document.getElementById(this.containerId);
this.listContainerToRender.innerHTML = `
`
this.listContainerToRender.classList.add('swym-storefront-layout-root-component');
} catch (error) {
window._swat?.utils.warn('Invalid List Container Selector ', this.containerId);
}
}
}
reRenderUI() {
this.renderUI();
}
}
/**
* SwymStorefrontLayoutAsDrawer
*
* This class extends SwymWishlistCore to implement a drawer-style storefront wishlist layout.
* It provides an interactive UI for users to view and manage their wishlist within a side drawer.
*
* Features:
* - Renders a wishlist drawer that slides in/out based on user interaction.
* - Supports collection carousel display based on SwymStorefrontLayoutContext settings.
* - Includes login UI for authentication-related actions.
* - Implements event listeners for closing the drawer via a close button or backdrop click.
* - Triggers instrumentation events for UI engagement tracking.
*
* Methods:
* - renderUI(): Generates the wishlist drawer UI and injects it into the component.
* - initUIElement(): Caches DOM elements required for interactions.
* - attachDrawerEventListner(): Attaches event listeners for closing the drawer.
* - open(): Opens the drawer and prevents background scrolling.
* - close(): Closes the drawer, restores scrolling, and updates browser history.
* - reRenderUI(): Re-renders the UI and retains the open state if applicable.
*
* Usage:
*
*/
class SwymStorefrontLayoutAsDrawer extends SwymWishlistCore {
constructor() {
super();
this.renderUI();
}
renderUI() {
this.innerHTML = `
`
this.initUIElement();
}
initUIElement() {
this.elements = {
drawer: this.querySelector('.swym-storefront-layout-drawer'),
drawerCloseButton: this.querySelector('#swym-storefront-layout-close-drawer-button'),
drawerbackdrop: this.querySelector('.swym-storefront-layout-backdrop'),
collectionList: this.querySelector('#swym-storefront-layout-collection-list')
}
this.attachDrawerEventListner();
}
attachDrawerEventListner() {
this.elements.drawerCloseButton.addEventListener('click', this.close.bind(this));
this.elements.drawerbackdrop.addEventListener('click', this.close.bind(this));
}
open() {
this.isOpen = true;
if (this.elements && this.elements.drawer) {
this.elements.drawer.classList.remove('swym-storefront-layout-hide-view');
document.body.classList.add('swym-storefront-layout-body-no-scroll');
window._swat?.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutOpened, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
}
}
close() {
this.isOpen = false;
if (this.elements && this.elements.drawer) {
this.elements.drawer.classList.add('swym-storefront-layout-hide-view');
document.body.classList.remove('swym-storefront-layout-body-no-scroll');
history.replaceState(null, '', window.location.pathname + window.location.search);
window._swat?.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutClosed, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
}
}
reRenderUI() {
this.renderUI();
if (this.isOpen) {
this.open();
}
}
}
/**
* SwymStorefrontLayoutCollectionCarousel
*
* This custom Web Component is responsible for rendering a carousel of collection lists
* within the storefront layout. It dynamically updates based on the provided collection
* data and offers smooth scrolling functionality with navigation buttons.
*
* Features:
* - Dynamically renders collections with images and item counts.
* - Implements smooth scrolling with previous/next buttons.
* - Updates button visibility based on scroll position.
* - Tracks user interactions using Swym's instrumentation.
* - Provides an action button for each collection with a tooltip menu.
* - Supports localization via `SwymStorefrontLayoutContext?.Strings`.
*
* Usage:
* - Call `setData({ collections })` to populate the carousel with collection data.
*
* Dependencies:
* - `window.SwymStorefrontLayoutContext` for localized strings and configurations.
* - `window._swat?.instrumentV3` for tracking user interactions.
* - `SwymStorefrontLayoutExtensions?.SwymStorefrontLayoutActionTooltip` for managing action tooltips.
*
*/
class SwymStorefrontLayoutCollectionCarousel extends HTMLElement {
constructor() {
super();
this.collections = [];
this.renderUI();
this.elements = {
title: this.querySelector('.swym-storefront-layout-collection-carousel-title'),
carouselContainer: this.querySelector('.swym-storefront-layout-carousel-container'),
carousel: this.querySelector('#swym-storefront-layout-collection-carousel-items-container'),
carouselPrevButton: this.querySelector('.swym-storefront-layout-carousel-prev-btn'),
carouselNextButton: this.querySelector('.swym-storefront-layout-carousel-next-btn')
}
this.attachEventListner();
}
setData({ collections }) {
this.collections = collections;
this.renderCollections();
}
renderUI() {
this.innerHTML = `
`;
}
return '';
}
renderOptionButton() {
// FIXME - remove repetative code once testing is done
const isOldControlCentre = !('multiple-wishlist' in (window?.SwymEnabledCommonFeatures || {}));
// Determine the boolean condition based on whether it's the old or new control centre
const shouldAddToCollection = isOldControlCentre
? SwymStorefrontLayoutContext?.Settings?.EnableStorefrontLayoutCollection // For old control centre, use this setting
: window?.SwymEnabledCommonFeatures?.['multiple-wishlist']; // For new control centre, use this feature flag
if (shouldAddToCollection || SwymStorefrontLayoutContext?.checkUserCanEditList(this.list || this.sflList)) {
return `
`
const addToCartBtn = this.querySelector(".swym-storefront-layout-grid-item-add-to-cart-button");
if (addToCartBtn) {
addToCartBtn.addEventListener("click", (e) => {
this.handleAddToCart(e, window.SwymParsedSampleProduct)
});
}
return;
}
// FIXME - remove repetative code once testing is done
const isOldControlCentre = !('multiple-wishlist' in (window?.SwymEnabledCommonFeatures || {}));
// Determine the boolean condition based on whether it's the old or new control centre
const shouldAddToCollection = isOldControlCentre
? SwymStorefrontLayoutContext?.Settings?.EnableStorefrontLayoutCollection // For old control centre, use this setting
: window?.SwymEnabledCommonFeatures?.['multiple-wishlist']; // For new control centre, use this feature flag
this.innerHTML = `
`;
}
}
static get observedAttributes() {
return ['loading', 'width', 'height'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'loading') {
if (newValue === 'true') {
this.style.display = 'flex';
} else {
this.style.display = 'none';
}
} else if (name == 'width') {
this.style.width = newValue;
} else if (name == 'height') {
this.style.height = newValue;
}
}
}
/**
* SwymStorefrontLayoutTitle Web Component
*
* This custom element is responsible for rendering the title section of the storefront layout,
* including the wishlist title and total item count.
*
* Functionality:
* - Displays the wishlist title using `SwymStorefrontLayoutContext?.Strings?.title`.
* - Shows the total count of wishlist items retrieved from `SwymStorefrontLayoutContext?.lists`.
* - Listens for the `WishlistFetched` event and updates the title dynamically when the wishlist is fetched.
*
* Usage:
*
*/
class SwymStorefrontLayoutTitle extends HTMLElement {
constructor() {
super();
this.renderTitle();
document.addEventListener(SwymStorefrontLayoutContext?.CustomEvents?.WishlistFetched, () => {
this.renderTitle();
})
}
renderTitle() {
const totalCount = SwymStorefrontLayoutContext?.lists?.reduce((total, list) => total + list.listcontents?.length, 0) || 0;
this.innerHTML = `
`;
}
}
/**
* SwymStorefrontLayoutLoggedUser Web Component
*
* This custom element handles user authentication UI within the storefront layout.
*
* Functionality:
* - Checks if a user is logged in using `SwymStorefrontLayoutContext?.isShopperLoggedIn`.
* - Displays a login prompt if the user is not logged in (when `showLogin="true"`).
* - Shows a welcome message with the user's name or email (when `showuser="true"`).
* - Registers a callback in `window.SwymCallbacks` to update UI when Swym state changes.
* - Tracks login button clicks via `SwymStorefrontLayoutExtensions?.InstrumentActionCodes`.
*
* Attributes:
* - `showuser` (boolean): Determines whether to display logged-in user details.
* - `showLogin` (boolean): Determines whether to display the login prompt.
*
* Usage:
*
*/
class SwymStorefrontLayoutLoggedUser extends HTMLElement {
constructor() {
super();
if (!window.SwymCallbacks) {
window.SwymCallbacks = [];
}
window.SwymCallbacks.push(this.swymCallbackFn.bind(this));
}
swymCallbackFn(swat) {
const showUser = this.getAttribute('showuser') === 'true';
const showLogin = this.getAttribute('showLogin') === 'true';
let isUserLogged = SwymStorefrontLayoutContext?.isShopperLoggedIn;
if (!isUserLogged && showLogin) {
this.renderLoginContainer();
} else if (isUserLogged && showUser) {
this.renderUserDetails();
}
}
handleLoginButtonClick = (event) => {
event.preventDefault();
window._swat?.instrumentV3(SwymStorefrontLayoutExtensions?.InstrumentActionCodes?.StorefrontLayoutUserLogIn, { "utm-term": SwymStorefrontLayoutExtensions?.InstrumentUtmTerms?.StorefrontLayoutUiEngagement });
};
renderUserDetails() {
let customer = SwymStorefrontLayoutContext?.SwymCustomerData;
this.innerHTML = `