{"version":3,"sources":["webpack:///./src/EbaySweden.TouchWeb/static/script/packages/debounce.js","webpack:///./src/EbaySweden.TouchWeb/static/script/packages/in-viewport.js","webpack:///./src/EbaySweden.TouchWeb/static/script/packages/format.js","webpack:///./src/EbaySweden.TouchWeb/static/script/packages/logger.js","webpack:///./src/frontend/lang/translate.jsx","webpack:///./src/frontend/constants/endpoints.js","webpack:///./src/frontend/lang/boot-languages.js","webpack:///./src/frontend/services/socket-io-channel.js","webpack:///./src/frontend/utils/http.js","webpack:///./src/frontend/constants/hosts.js","webpack:///./src/frontend/utils/url.js","webpack:///./src/frontend/utils/format.js","webpack:///./src/frontend/services/toast-queue.js","webpack:///./src/frontend/components/toasts/item-toast.module.scss","webpack:///./src/frontend/components/toasts/item-toast.jsx","webpack:///./src/frontend/services/toasts.js","webpack:///./src/frontend/services/boot-site-wide-notifications.js","webpack:///./src/EbaySweden.TouchWeb/static/script/app.js","webpack:///./src/frontend/apps/tradera/configure-dayjs.js","webpack:///./src/frontend/utils/time-api.js","webpack:///./src/frontend/utils/server-date.js","webpack:///./src/EbaySweden.TouchWeb/static/script/packages/init-data.js","webpack:///./src/frontend/apps/syi/script/app_react/utils/language.js","webpack:///./src/EbaySweden.TouchWeb/static/script/utils/modules.js","webpack:///./src/frontend/state/environment/reducer.js","webpack:///./src/frontend/utils/api.js","webpack:///./src/frontend/services/global-socket.js","webpack:///./src/frontend/state/environment/actions.js","webpack:///./src/frontend/components/alink/alink.jsx","webpack:///./src/frontend/utils/is-prerender.js","webpack:///./src/EbaySweden.TouchWeb/static/script/packages/analytics.js","webpack:///./src/EbaySweden.TouchWeb/static/script/app/ui/google-tagmanager-service.js"],"names":["debounce","func","wait","immediate","timeout","context","this","args","arguments","later","apply","callNow","clearTimeout","isLocaleFormattingSupportedInBrowser","toLocaleString","e","name","toLocaleStringSupportsLocales","Intl","NumberFormat","formatNumber","number","format","formatMe","undefined","logger","error","scope","sentryException","Error","Sentry","NS_TOUCHWEB","I18N_NAMESPACES","TRANS_SUFFIX","useTranslator","useTranslation","t","ready","wrappedT","useCallback","i18nKey","withTranslator","WrappedComponent","WithTranslator","props","displayName","withUrlLocalizer","WithUrlLocalizer","toLocalizedUrl","useUrlLocalizer","useCurrentLanguage","i18n","language","urlLocalizer","useRef","url","current","Trans","children","defaults","ns","webApiUrl","initData","touchWebUrl","AVAILABLE_SHIPPING_COUNTRIES","BANK_ID_AUTHENTICATE","BANK_ID_PROGRESS","BRAND_LIST_PAGE","BRAND_PAGE","CAMPAIGN","campaignId","replace","CART_UPDATE_SUMMARY","CART_OVERVIEW_VIEW","CART_ADD_ITEM","CART_REMOVE_ITEMS","CART_SET_ITEM_QUANTITY","CHARITY_EARNINGS_TICKER","CMS_API","cmsApiUrl","COMBINED_SHIPPING_UPSELL","FAVORITE_SELLER_ADD","FAVORITE_SELLER_REMOVE","FAVOURITE_SELLERS","GEO_PUBLIC_API_URL","geoPublicApiUrl","GET_PROFILE_FEEDBACK_ITEMS","HYPERWALLET_PAYOUT_COMPLETE","HYPERWALLET_PAYOUT_TOKEN","HYPERWALLET_PAYOUT","INTERNATIONAL_SHIPPING_CALCULATOR","ITEM_DESCRIPTION","itemId","ITEM_DISCOUNT_QUOTA","LAST_CHANCE","LIVE_SHOPPING_PUBLIC_API","MEMBER_PAYOUT_SETTINGS_REMOVE","MEMBER_PAYOUT_SETTINGS","MEMBER_SYSTEM_MESSAGES","ORDER_CHECKOUT_AUTH_DATA","ORDER_CHECKOUT_BRAINTREE","ORDER_CHECKOUT_COMPLETE_PAYMENT","ORDER_CHECKOUT_CONFIRMATION","ORDER_CHECKOUT_INIT_PAYMENT","ORDER_CHECKOUT_PAYMENT_OPTIONS","ORDER_CHECKOUT_PAYMENT_STATUS","ORDER_CHECKOUT_PAYMENT","orderCheckoutPaymentUrl","ORDER_CHECKOUT_VIEW","ORDER_CHECKOUT_REQUEST_COMBINED_PRICE","ORDER_CHECKOUT_CANCEL_PAYMENT","ORDER_CHECKOUT_CREATE_UNCOMMITTED_PURCHASE_ORDER","ORDER_PURCHASE_BIN","ORDER_PURCHASE_SHOP_ITEMS","PAYMENT_SWISH_OPTOUT","PERSONALISED_SUGGESTIONS","SEARCH_SUGGESTIONS","SEARCH","SELLING_ATTRIBUTES","SELLING_DRAFT_IMAGE_COLORS","SELLING_CAMPAING_CODE","SELLING_CATEGORY_RESTRICTIONS","SELLING_DRAFT_LOAD_FROM_TEMPLATE","SELLING_DRAFT_SAVE","SELLING_DRAFT","draftId","SELLING_DRAFTS_DELETE","SELLING_DRAFTS","SELLING_ITEM_PUBLISH","SELLING_ITEM_STATUS","SELLING_ITEM_UPDATE","SELLING_PREVIEW","SELLING_SCRIBE_DURATION","SELLING_SCRIBE_INCREMENT","SELLING_SCRIBE_SESSION_DURATION","SELLING_SCRIBE_SESSION_START","SELLING_SCRIBE_VALIDATION_ERRORS","SELLING_SHIPPING_CALCULATOR","SELLING_SUGGEST_ATTRIBUTES","SELLING_TEMPLATE_SAVE","SELLING_TEMPLATE","templateId","SELLING_TEMPLATES_COUNT","SELLING_TEMPLATES_DELETE","SELLING_TEMPLATES","SETTINGS","SHIPPING_PROVIDERS","TOUCHWEB_URL","TRANSLATE_PROFILE_FEEDBACKITEMS","WEB_API","WISHLIST","WISHLIST_ADD","WISHLIST_REMOVE","START_OFF_PLATFORM_CHECKOUT","UPI","purchaseOrderId","INR","PURCHASE_ORDER","MARKETING_PUBLIC_API","i18nInitialized","bootLanguages","translations","window","touchwebTranslations","attributeTranslations","options","translationResources","key","value","namespace","attributeResources","resources","prev","s","use","initReactI18next","LanguageDetector","init","detection","order","htmlTag","document","html","defaultNS","fallbackLng","debug","keySeparator","interpolation","escape","str","formatNumberWithSeparators","react","useSuspense","missingKeyLoggingConfig","err","saveMissing","saveMissingTo","missingKeyHandler","missingInterpolationHandler","text","whenInitialized","then","getCurrentLanguage","MissingSocketIoServerUrl","ReferenceError","MissingRoomId","isAllowedToConnect","isPrerender","navigator","userAgent","SocketIoChannel","constructor","socketIoServerUrl","autoConnect","socket","io","events","rooms","on","room","join","payload","Type","callback","Event","contexts","socketIo","type","connect","isConnected","emit","has","add","leave","rejoinOnConnect","delete","addEventListener","event","removeEventListener","off","connected","disconnect","httpClient","baseUrl","shouldLocalizeUrl","axiosWrapper","httpClientConfig","axiosCaller","cancelTokenId","axiosConfig","version","utilizeCancelToken","cancel","cancelToken","safeUrl","substring","getSafeUrl","localizedUrl","getLanguage","axiosWithTokenRefresh","checkResponseVersion","response","finalizeResponse","catch","handleError","get","axiosConfigs","authenticated","axios","config","post","put","trpcClient","endpoint","client","unpackResponse","data","command","query","defaultClient","touchWebClient","webApiClient","ENDPOINTS","liveShoppingApiClient","marketingApiClient","memberIdentificationClient","translationOnDemandClient","SPA_PATH_REGEX","RegExp","SUPPORTED_LANGUAGES","formatQueryParams","queryParams","categoryId","formattedQueryParams","isSpaLink","urlOrPath","pathname","test","stripCategoryIdFromQueryParameters","stripHost","HOSTS","stripItmFromQueryParameters","itm_source","itm_medium","stripPaginationFromQueryParameters","spage","paging","page","fe","stripSavedQueryNameFromQueryParameters","savedQueryName","toAbsoluteUrl","relativeUrl","toAbsoluteUrlFromObject","search","languageCodeIso2","ignoredUrls","domain","isAbsolute","isAbsoluteUrl","urlObject","origin","localisedPathname","setLanguagePrefix","toQueryParameters","qs","parse","ignoreQueryPrefix","toRelativeTraderaUrl","toSearchString","addQueryPrefix","encode","skipNulls","arrayFormat","stringify","path","languagePrefix","matches","match","firstMatch","index","getLanguagePrefixFromUrl","getBackToHereRedirectUrl","location","forceRedirect","Math","round","random","protocol","host","formatStaticEndTime","endDateInput","dayjs","formatEndDate","nowDateInput","endDate","now","isSameOrAfter","hours","diff","minutes","timeParts","push","count","isAfter","separator","toString","Number","formatSellerDsrAverage","locale","minimumFractionDigits","maximumFractionDigits","formatPrice","price","formattedPrice","opts","style","currency","currencyDisplay","useGrouping","formatDateWithDayOfWeek","dateString","weekday","year","month","day","DateTimeFormat","Date","items","inProgress","ItemToast","imageUrl","itemUrl","shortDescription","eventData","useLink","href","className","styles","src","title","alt","ToastMessage","message","newLeadingBidAmount","timeLeftMinutes","queuedToasts","item","ttlInMinutes","timeStamp","next","itemData","shift","notifyDone","isInProgress","getLength","length","openNextToast","a","nextItem","queueLength","toast","React","createElement","autoClose","max","onClose","handleNotification","visibilityState","showItemOutbiddedToast","showItemFirstBidToast","showItemSoldToast","showItemWonToast","showItemPaidToast","showItemWishListReminderToast","refreshLoginState","isLoggedIn","extend","isBetween","getServerDate","gtm","loadGtmScript","featureSwitches","socketUrl","joinMemberRoom","getGlobalSocket","isRetry","success","ItemId","NewLeadingBidAmount","Price","TimeLeftMinutes","bootSiteWideNotifications","webLiveUrl","memberId","module","split","isSpaModule","loadSpaModule","initModule","default","loadModule","loadedModule","runModule","body","setAttribute","handleModuleError","queryServerTime","retryCount","latencyLimit","maxRetries","requestStart","currentTime","start","latency","getServerTime","_minServerCheckInterval","_serverDiff","_didGetServerResponse","_lastCheckAtMs","updateServerDiff","serverTimeObject","timeNowOnServer","getTime","_initialPromise","promise","initDataEL","getElementById","getAttribute","JSON","getInitData","toLocalizedRiotUrl","querySelector","isSinglePageApp","console","slice","createSlice","initialState","reducers","setEnvironmentHash","state","environmentHash","setIsSpaNavigationEnabled","isSpaNavigationEnabled","actions","reducer","API_ERRORS","IGNORE_ME","ABORTED","CANCELLED","NETWORK","TIMEOUT","VERSION_MISMATCH","LOGGED_OUT","defaultJsonRequestHeaders","Accept","withCredentials","headers","notAuthenticated","isUnauthorized","statusCode","submitOriginalRequest","antiCacheRegExp","handleMissingAuthToken","refreshAccessToken","handleErrorAfterRefresh","errorAfterRefreshToken","request","status","reject","handleUnauthorized","checkLoginState","errorResponseInterceptor","responseString","responseStatus","errorCode","isMissingAuthToken","axiosInstance","instance","create","interceptors","cancelTokens","tokenId","CancelToken","source","token","checkResponseLoggedOut","statusHandlers","isCancel","reloadOnUnauthorized","reload","logError","globalSocket","updateEnvironmentHash","dispatch","getState","environment","ALink","givenOnClick","onClick","otherProps","useDispatch","useSelector","to","evt","propTypes","defaultProps","pushToDataLayer","dataLayer","trackPageView","ga","isNonInteractive","analyticsData","userTriggered","trackTiming","category","variable","label","trackEvent","eventCategory","eventAction","action","eventLabel","eventValue","eventNonInteractive","hitCallback","level","Info","spaPageViewTrackingEnabled","_newPageFromServer","w","d","l","i","f","getElementsByTagName","j","async","parentNode","insertBefore","_getDatalayerObject","output","entry","_reset","newSpaPage","pageType","_pushInitialDataLayer","legacyDataLayer","_buildFromInitData","userLanguage","memberEmail","memberHashedEmail","memberEmailSha256","memberEmailMd5","memberFirstName","memberLastName","memberCountry","loginState","isNotInIframe","self","top","blueshiftEventApiKey","isNativeAppContext","isQuantcastConsentEnabled","isDigitalAudienceTrackingEnabled","quantcastSite","initialDataLayer","splitTestGroups","trackAction","nonInteractive","trackGtmEvent","eventName","trackLinkClickAndCallback","eventCallback","trackLinkClickAndGotoUrl"],"mappings":"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","file":"script/chunks/chunk.default~info.3c858e36bd.js","sourcesContent":["/**\n * Debounce function\n * Borrowed from underscore;\n */\nconst debounce = function(func, wait, immediate) {\n let timeout;\n return function() {\n let context = this,\n args = arguments;\n let later = function() {\n timeout = null;\n if (!immediate) {\n func.apply(context, args);\n }\n };\n let callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow) {\n func.apply(context, args);\n }\n };\n};\n\nexport default debounce;\n","const inViewport = (selector, callback, options, ...args) => {\n const El = Array.from(document.querySelectorAll(selector));\n\n if (El) {\n if ('IntersectionObserver' in window) {\n let defaultOptions = {\n root: null,\n rootMargin: '0px',\n threshold: 0\n };\n\n let observer = new IntersectionObserver(\n entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n callback(entry.target, args);\n observer.unobserve(entry.target);\n }\n });\n },\n { defaultOptions, ...options }\n );\n\n El.forEach(app => {\n observer.observe(app);\n });\n } else {\n callback(El[0], args);\n }\n }\n};\n\nexport default inViewport;\n","// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString\nfunction toLocaleStringSupportsLocales() {\n let number = 0;\n try {\n number.toLocaleString('i');\n } catch (e) {\n return e.name === 'RangeError';\n }\n return false;\n}\n\n// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString\nfunction toLocaleStringSupportsOptions() {\n return !!(\n typeof Intl === 'object' &&\n Intl &&\n typeof Intl.NumberFormat === 'function'\n );\n}\n\nconst isLocaleFormattingSupportedInBrowser =\n toLocaleStringSupportsLocales() && toLocaleStringSupportsOptions();\n\nexport const formatPrice = price => {\n if (!isLocaleFormattingSupportedInBrowser) {\n return typeof price !== 'number'\n ? `${parseInt(price)} kr`\n : `${price} kr`;\n }\n\n const format = formatMe =>\n formatMe.toLocaleString('sv-SE', {\n symbol: ' kr',\n symbolPosition: 'end',\n decimal: ',',\n comma: '.'\n });\n return typeof price !== 'number'\n ? `${format(parseInt(price))} kr`\n : `${format(price)} kr`;\n};\n\nexport const formatNumber = number => {\n if (!isLocaleFormattingSupportedInBrowser) {\n return typeof number !== 'number' ? `${parseInt(number)}` : `${number}`;\n }\n\n const format = formatMe => formatMe.toLocaleString('sv-SE');\n\n return number !== undefined\n ? typeof number !== 'number'\n ? format(parseInt(number))\n : format(number)\n : '';\n};\n\nexport const formatUserRating = rating => {\n if (!rating) return;\n const number = parseFloat(rating);\n if (number <= 0) return '0.0';\n if (number >= 5) return '5.0';\n return number.toFixed(1);\n};\n","import * as Sentry from '@sentry/browser';\n\n/**\n * @param {object} error - takes an exception and logs to Sentry or the console in development\n * @param {object} [scope] - Sentry CaptureContext created with new Sentry.Scope() or plain object\n * @desc logger is designed for logging errors. It will accept an argument of any type and create a stacktrace containing a reference to the callee.\n * @TODO Migrate this functionality to a logging module that handles different levels of logs\n */\nconst logger = (error, scope) => {\n let sentryException;\n if (error instanceof Error) {\n sentryException = error;\n } else if (typeof error === 'string') {\n sentryException = new Error(error);\n } else {\n sentryException = new Error(JSON.stringify(error));\n }\n if (scope) {\n Sentry.captureException(sentryException, scope);\n } else {\n Sentry.captureException(sentryException);\n }\n};\n\nexport default logger;\n","import React, { useCallback, useRef } from 'react';\nimport { useTranslation, Trans as TransComponent } from 'react-i18next';\nimport { toLocalizedUrl } from 'tradera-utils/url';\n\nconst NS_TOUCHWEB = 'touchWeb';\nconst NS_ATTRIBUTES = 'attributes';\nconst I18N_NAMESPACES = [NS_TOUCHWEB, NS_ATTRIBUTES];\nconst TRANS_SUFFIX = 'Trans';\n\n/**\n * i18next translation wrappers for translating static text in react components\n * When to use what?\n * -----\n * 1. For functional components use `useTranslator()` hook\n * 2. For class components use `withTranslator()` HOC\n */\n\n/**\n * Translation hook, wrapper for react-i18next\n * @return {{t: Function}}\n */\n\nexport const useTranslator = () => {\n const { t, ready } = useTranslation(I18N_NAMESPACES, {\n wait: true\n });\n const wrappedT = useCallback(\n (...args) => {\n const i18nKey = args[0];\n if (i18nKey.endsWith(TRANS_SUFFIX)) {\n throw new Error(\n `t function keys should not have \"Trans\" suffix, got key \"${i18nKey}\". Use Trans component instead.`\n );\n }\n return t(...args);\n },\n [t]\n );\n return { t: ready ? wrappedT : () => '...' };\n};\n\n/**\n * Translation HOC, wrapper for react-i18next\n * @param {Component} WrappedComponent\n * @return {Component} The wrapped component.\n */\nexport function withTranslator(WrappedComponent) {\n function WithTranslator(props) {\n const { t } = useTranslator();\n return ;\n }\n\n WithTranslator.displayName = `withTranslator(${WrappedComponent.displayName ||\n WrappedComponent.name}`;\n return WithTranslator;\n}\n\n/**\n * Localization HOC, wrapper for URL-localizer\n * @param {Component} WrappedComponent\n */\nexport function withUrlLocalizer(WrappedComponent) {\n function WithUrlLocalizer(props) {\n const { toLocalizedUrl } = useUrlLocalizer();\n return ;\n }\n\n WithUrlLocalizer.displayName = `withUrlLocalizer(${WrappedComponent.displayName ||\n WrappedComponent.name}`;\n\n return WithUrlLocalizer;\n}\n\n/**\n * Current language hook, wrapper for react-i18next\n * @return {{language: string}}\n */\nexport const useCurrentLanguage = () => {\n const { i18n, ready } = useTranslation(undefined, { wait: true });\n return {\n language: ready ? i18n.language : null\n };\n};\n\n/**\n * Returns function to append language prefix to link\n * @return {{toLocalizedUrl: function}}\n */\nexport const useUrlLocalizer = () => {\n const { i18n, ready } = useTranslation(undefined, { wait: true });\n const urlLocalizer = useRef(url => toLocalizedUrl(url, i18n.language));\n return { toLocalizedUrl: ready ? urlLocalizer.current : url => url };\n};\n\nexport const Trans = props => {\n const { t, ready } = useTranslation(I18N_NAMESPACES, {\n wait: true\n });\n const { i18nKey, children, defaults } = props;\n if (!i18nKey) {\n throw new Error('Trans component key must have a i18nKey property');\n }\n if (!i18nKey.endsWith(TRANS_SUFFIX)) {\n throw new Error(\n `Trans component key must have the \"Trans\" suffix, got key \"${i18nKey}\"`\n );\n }\n if (children) {\n throw new Error(\n `Trans component must not have children, use components or t('${i18nKey}') function instead`\n );\n }\n if (defaults) {\n throw new Error(\n 'Trans components must not have defaults, use lokalise intead.'\n );\n }\n if (!ready) {\n return '...';\n }\n return ;\n};\n","import initData from 'init-data';\n\nconst { webApiUrl, touchWebUrl } = initData;\n\nexport default {\n AVAILABLE_SHIPPING_COUNTRIES:\n webApiUrl + '/member/getavailablecountriesforshipping',\n BANK_ID_AUTHENTICATE: touchWebUrl + 'bankid/authenticate',\n BANK_ID_PROGRESS: touchWebUrl + 'bankid/progress',\n BRAND_LIST_PAGE: touchWebUrl + 'brands/api',\n BRAND_PAGE: touchWebUrl + 'brand/api/',\n CAMPAIGN: campaignId =>\n touchWebUrl +\n 'campaign/api/{campaignId}'.replace('{campaignId}', campaignId),\n CART_UPDATE_SUMMARY: touchWebUrl + 'shopping/managecart/updatecartsummary',\n CART_OVERVIEW_VIEW: webApiUrl + '/shopping/checkout/cartoverview',\n CART_ADD_ITEM: webApiUrl + '/shopping/cart/item',\n CART_REMOVE_ITEMS: webApiUrl + '/shopping/cart/removeitems',\n CART_SET_ITEM_QUANTITY: webApiUrl + '/shopping/cart/setitemquantity',\n CHARITY_EARNINGS_TICKER:\n touchWebUrl + 'cache/kampanjer/earningsticker/earnings',\n CMS_API: initData.cmsApiUrl,\n COMBINED_SHIPPING_UPSELL: touchWebUrl + 'combined-shipping-upsell/items',\n FAVORITE_SELLER_ADD: touchWebUrl + 'my/favourite-sellers/add',\n FAVORITE_SELLER_REMOVE: touchWebUrl + 'my/favourite-sellers/remove',\n FAVOURITE_SELLERS: webApiUrl + `/discover/favouritesellers-and-items2`,\n GEO_PUBLIC_API_URL: initData.geoPublicApiUrl,\n GET_PROFILE_FEEDBACK_ITEMS: touchWebUrl + 'profile/model',\n HYPERWALLET_PAYOUT_COMPLETE:\n webApiUrl + '/member/paymentprovider/completehyperwallettransfermethod',\n HYPERWALLET_PAYOUT_TOKEN:\n webApiUrl + '/member/paymentprovider/hyperwalletauthenticationtoken',\n HYPERWALLET_PAYOUT:\n webApiUrl +\n '/member/paymentprovider/hyperwallettransfermethodviewmodel',\n INTERNATIONAL_SHIPPING_CALCULATOR:\n webApiUrl + '/browse/internationalshippingcalculator',\n ITEM_DESCRIPTION: itemId =>\n `${webApiUrl}/browse/item/${itemId}/description`,\n ITEM_DISCOUNT_QUOTA: touchWebUrl + 'profile/shop-item-settings/quotas',\n LAST_CHANCE: touchWebUrl + 'StartPage/LastChance',\n LIVE_SHOPPING_PUBLIC_API: '/api/live',\n MEMBER_PAYOUT_SETTINGS_REMOVE:\n webApiUrl + '/member/profile/removetraderapaypayoutdestination',\n MEMBER_PAYOUT_SETTINGS:\n webApiUrl + '/member/paymentprovider/memberpayoutsettingsviewmodel',\n MEMBER_SYSTEM_MESSAGES: webApiUrl + '/member/system-messages',\n ORDER_CHECKOUT_AUTH_DATA:\n webApiUrl +\n '/shopping/ordercheckout/purchaseorderpaymentattemptauthenticationdata',\n ORDER_CHECKOUT_BRAINTREE:\n webApiUrl + '/shopping/ordercheckout/purchaseorderbraintreeclienttoken',\n ORDER_CHECKOUT_COMPLETE_PAYMENT:\n webApiUrl +\n '/shopping/ordercheckout/completepurchaseorderpaymentattempt',\n ORDER_CHECKOUT_CONFIRMATION:\n webApiUrl +\n '/shopping/ordercheckout/purchaseordercheckoutconfirmationviewmodel',\n ORDER_CHECKOUT_INIT_PAYMENT:\n webApiUrl +\n '/shopping/ordercheckout/initializepurchaseorderpaymentattempt',\n ORDER_CHECKOUT_PAYMENT_OPTIONS:\n webApiUrl + '/shopping/ordercheckout/purchaseorderpaymentoptions',\n ORDER_CHECKOUT_PAYMENT_STATUS:\n webApiUrl + '/shopping/ordercheckout/purchaseorderpaymentattemptstatus',\n ORDER_CHECKOUT_PAYMENT: initData.orderCheckoutPaymentUrl,\n ORDER_CHECKOUT_VIEW:\n webApiUrl + '/shopping/ordercheckout/purchaseordercheckoutviewmodel',\n ORDER_CHECKOUT_REQUEST_COMBINED_PRICE:\n webApiUrl + '/shopping/ordercheckout/requestcombinedshippingprice',\n ORDER_CHECKOUT_CANCEL_PAYMENT:\n webApiUrl + '/shopping/ordercheckout/cancelpurchaseorderpaymentattempt',\n ORDER_CHECKOUT_CREATE_UNCOMMITTED_PURCHASE_ORDER:\n webApiUrl + '/shopping/ordercheckout/createuncommittedpurchaseorder',\n ORDER_PURCHASE_BIN: webApiUrl + '/shopping/ordercheckout/purchasebin',\n ORDER_PURCHASE_SHOP_ITEMS:\n webApiUrl + '/shopping/ordercheckout/purchaseshopitems',\n PAYMENT_SWISH_OPTOUT: touchWebUrl + 'my/payments2/OptOut',\n PERSONALISED_SUGGESTIONS: '/api/personalised-suggestions',\n SEARCH_SUGGESTIONS: touchWebUrl + 'search/suggestions',\n SEARCH: touchWebUrl + 'search',\n SELLING_ATTRIBUTES: webApiUrl + '/selling/attributes',\n SELLING_DRAFT_IMAGE_COLORS: webApiUrl + '/images/colors',\n SELLING_CAMPAING_CODE: touchWebUrl + 'selling/api/campaign',\n SELLING_CATEGORY_RESTRICTIONS: webApiUrl + '/selling/category-restriction',\n SELLING_DRAFT_LOAD_FROM_TEMPLATE:\n touchWebUrl + 'selling/api/drafts/from-template',\n SELLING_DRAFT_SAVE: touchWebUrl + 'selling/api/drafts/',\n SELLING_DRAFT: draftId => touchWebUrl + `selling/api/drafts/${draftId}`,\n SELLING_DRAFTS_DELETE: touchWebUrl + 'selling/api/drafts/delete',\n SELLING_DRAFTS: touchWebUrl + 'selling/api/drafts/',\n SELLING_ITEM_PUBLISH: touchWebUrl + 'selling/api/items',\n SELLING_ITEM_STATUS: itemId =>\n touchWebUrl + `selling/api/items/${itemId}/status`,\n SELLING_ITEM_UPDATE: itemId =>\n touchWebUrl + `selling/api/items/${itemId}/update`,\n SELLING_PREVIEW: draftId =>\n touchWebUrl + `selling/api/drafts/preview/${draftId}`,\n SELLING_SCRIBE_DURATION: touchWebUrl + 'selling/api/scribe/duration',\n SELLING_SCRIBE_INCREMENT: touchWebUrl + 'selling/api/scribe/increment',\n SELLING_SCRIBE_SESSION_DURATION:\n touchWebUrl + 'selling/api/scribe/session-duration',\n SELLING_SCRIBE_SESSION_START:\n touchWebUrl + 'selling/api/scribe/session-start',\n SELLING_SCRIBE_VALIDATION_ERRORS:\n touchWebUrl + 'selling/api/scribe/form-validation-errors',\n SELLING_SHIPPING_CALCULATOR: touchWebUrl + 'selling/shippingcalculator',\n SELLING_SUGGEST_ATTRIBUTES: webApiUrl + '/selling/suggest/attributes',\n SELLING_TEMPLATE_SAVE: touchWebUrl + 'selling/api/templates',\n SELLING_TEMPLATE: templateId =>\n touchWebUrl + `selling/api/templates/${templateId}`,\n SELLING_TEMPLATES_COUNT: touchWebUrl + 'selling/api/templates-count',\n SELLING_TEMPLATES_DELETE: touchWebUrl + 'selling/api/templates/delete',\n SELLING_TEMPLATES: touchWebUrl + 'selling/api/templates',\n SETTINGS: touchWebUrl + 'profile/shop-item-settings/settings',\n SHIPPING_PROVIDERS: webApiUrl + '/selling/shippingproviderswithproducts',\n TOUCHWEB_URL: touchWebUrl,\n TRANSLATE_PROFILE_FEEDBACKITEMS: webApiUrl + '/member/feedback/translated',\n WEB_API: webApiUrl,\n WISHLIST: touchWebUrl + 'my/api/wish-list',\n WISHLIST_ADD: touchWebUrl + 'shopping/wishlist/add',\n WISHLIST_REMOVE: touchWebUrl + 'shopping/wishlist/remove',\n START_OFF_PLATFORM_CHECKOUT:\n touchWebUrl + 'shopping/cartoverview/StartCheckoutSession',\n UPI: purchaseOrderId =>\n webApiUrl + '/member/uppo-strike/?PurchaseOrderId=' + purchaseOrderId,\n INR: purchaseOrderId =>\n webApiUrl + '/member/ponr-strike/?PurchaseOrderId=' + purchaseOrderId,\n PURCHASE_ORDER: purchaseOrderId =>\n webApiUrl + '/member/purchaseorder/?PurchaseOrderId=' + purchaseOrderId,\n MARKETING_PUBLIC_API: '/api/marketing'\n};\n","import i18n from 'i18next';\nimport { logger } from 'packages';\nimport { initReactI18next } from 'react-i18next';\nimport LanguageDetector from 'i18next-browser-languagedetector';\nimport { toLocalizedUrl } from 'tradera-utils/url';\nimport { formatNumberWithSeparators } from 'tradera-utils/format';\nimport 'dayjs/locale/sv';\nimport 'dayjs/locale/da';\nimport 'dayjs/locale/de';\n\nlet i18nInitialized;\n\n/**\n * Initialize function for i18next\n * Must be run before doing any translations\n * @param {Array} [translations]\n * @param {Object} [options]\n * @returns {Promise} - a promise to the i18next t function\n */\nexport const bootLanguages = (\n translations = window.touchwebTranslations,\n attributeTranslations = window.attributeTranslations,\n options = {}\n) => {\n const translationResources = Object.entries(translations).map(\n ([key, value]) => ({\n key,\n value,\n namespace: 'touchWeb'\n })\n );\n const attributeResources = Object.entries(\n attributeTranslations\n ).map(([key, value]) => ({ key, value, namespace: 'attributes' }));\n\n const resources = translationResources\n .concat(attributeResources)\n .reduce((prev, { key, value, namespace }) => {\n const s = prev[key] || {};\n s[namespace] = value;\n return {\n ...prev,\n [key]: s\n };\n }, {});\n\n i18nInitialized = i18n\n .use(initReactI18next)\n .use(LanguageDetector)\n .init(\n {\n detection: {\n order: ['htmlTag'],\n htmlTag: document.html\n },\n defaultNS: ['touchWeb'],\n ns: ['attributes'],\n fallbackLng: 'sv',\n resources,\n debug: false,\n keySeparator: false,\n interpolation: {\n escape: str => str.replace(/{{/g, '').replace(/}}/g, ''),\n format: (value, format) => {\n if (format === 'formatNumber') {\n return formatNumberWithSeparators(value);\n }\n\n return value;\n }\n },\n react: {\n useSuspense: false // loading from file currently breaks if this is true\n },\n ...missingKeyLoggingConfig,\n ...options\n },\n err => {\n if (err) {\n logger('error when loading translations', err);\n }\n }\n );\n\n return i18nInitialized;\n};\n\nconst missingKeyLoggingConfig = {\n saveMissing: true,\n saveMissingTo: 'current',\n missingKeyHandler: (language, namespace, key) => {\n logger(\n `TranslationMissing (javascript) - Unable to find key ${key} (namespace ${namespace}) in language ${language}!`\n );\n },\n missingInterpolationHandler: (text, value) => {\n logger(\n `InterpolationFailure (javascript) - Unable to interpolate the text \"${text}\" fully. The following placeholder values were missing: ${JSON.stringify(\n value\n )}`\n );\n return undefined;\n }\n};\n\n/**\n * This function helps you make sure that i18next init has completed before continuing\n */\nexport const whenInitialized = () => {\n if (!i18nInitialized) {\n throw new Error(\n \"Can't call boot-languages whenInitialized before init!\"\n );\n }\n return i18nInitialized.then(t => ({\n t,\n toLocalizedUrl: url => toLocalizedUrl(url, i18n.language)\n }));\n};\n\n/**\n * Only required for Storybook, do not use.\n */\nexport const changeLanguage = language => i18n.changeLanguage(language);\n\nexport const getCurrentLanguage = () => i18n.language;\n","import io from 'socket.io-client';\nimport logger from 'packages/logger';\nimport { isPrerender } from 'tradera-utils/is-prerender';\n\nexport class MissingSocketIoServerUrl extends ReferenceError {}\nexport class MissingRoomId extends ReferenceError {}\n\nconst isAllowedToConnect = !isPrerender(window?.navigator?.userAgent || '');\n\n/**\n * Connect to a socket.io channel & add callbacks for events it broadcasts\n * @param {string} socketIoServerUrl\n */\nexport class SocketIoChannel {\n constructor(socketIoServerUrl, autoConnect = false) {\n if (!socketIoServerUrl) {\n throw new MissingSocketIoServerUrl();\n }\n this.socket = io(socketIoServerUrl, {\n autoConnect: isAllowedToConnect && autoConnect\n });\n this.events = {};\n this.rooms = new Set();\n\n this.socket.on('connect', () => {\n // Rejoin room on reconnect if network connection is lost\n this.rooms.forEach(room => this.join(room));\n });\n\n this.socket.on('clientEvent', payload => {\n if (!payload.Type) {\n logger('socket.io missing clientEvent Type', {\n contexts: {\n socketIo: {\n payload\n }\n }\n });\n return;\n }\n const callback = this.events[payload.Type];\n if (callback) {\n callback(payload.Event, this);\n } else {\n logger(`socket.io unknown clientEvent type`, {\n contexts: {\n socketIo: {\n type: payload.Type\n }\n }\n });\n }\n });\n }\n\n connect() {\n if (isAllowedToConnect && !this.isConnected()) this.socket.connect();\n }\n\n join(room) {\n if (!room) {\n throw new MissingRoomId();\n }\n if (this.isConnected()) {\n this.socket.emit('join', room);\n }\n if (!this.rooms.has(room)) {\n // Queue join until connect\n this.rooms.add(room);\n }\n }\n\n leave(room, rejoinOnConnect = false) {\n if (!room) {\n throw new MissingRoomId();\n }\n if (this.isConnected() && this.rooms.has(room)) {\n this.socket.emit('leave', room);\n }\n if (!rejoinOnConnect) {\n this.rooms.delete(room);\n }\n }\n\n addEventListener(event, callback) {\n this.events[event] = callback;\n }\n\n removeEventListener(event) {\n delete this.events[event];\n }\n\n on(event, callback) {\n this.socket.on(event, callback);\n }\n\n off(event, callback) {\n this.socket.off(event, callback);\n }\n\n isConnected() {\n return this.socket?.connected;\n }\n\n disconnect() {\n if (!this || !this.isConnected()) return;\n this.rooms.forEach(room => this.leave(room, true));\n this.socket.disconnect();\n }\n}\n","import ENDPOINTS from 'tradera-constants/endpoints';\nimport {\n axiosWithTokenRefresh,\n checkResponseVersion,\n finalizeResponse,\n handleError,\n utilizeCancelToken,\n axiosConfigs\n} from 'tradera-utils/api';\nimport initData from 'init-data';\nimport { toLocalizedUrl } from 'tradera-utils/url';\nimport { getLanguage } from 'tradera-apps/syi/script/app_react/utils/language';\n\nexport const HTTP_STATUS_CODES = {\n NOT_FOUND: 404\n};\n\n// Prevents URL:s that begins with // when that was not intended.\nconst getSafeUrl = (baseUrl, url) => {\n if (baseUrl.endsWith('/') && url.startsWith('/')) {\n return baseUrl + url.substring(1);\n }\n return baseUrl + url;\n};\n\nconst httpClient = (baseUrl, shouldLocalizeUrl) => {\n const axiosWrapper = (url, httpClientConfig, axiosCaller) => {\n let { cancelTokenId, ...axiosConfig } = httpClientConfig;\n const version = initData.version;\n if (cancelTokenId) {\n const { cancel, cancelToken } = utilizeCancelToken(cancelTokenId);\n axiosConfig.cancelToken = cancelToken;\n if (cancel) {\n cancel();\n }\n }\n const safeUrl = getSafeUrl(baseUrl, url);\n const localizedUrl = shouldLocalizeUrl\n ? toLocalizedUrl(safeUrl, getLanguage())\n : safeUrl;\n return axiosCaller(axiosWithTokenRefresh(), localizedUrl, axiosConfig)\n .then(\n version ? checkResponseVersion(version) : response => response\n )\n .then(finalizeResponse())\n .catch(handleError());\n };\n\n return {\n get: (url, httpClientConfig = axiosConfigs.authenticated) => {\n return axiosWrapper(url, httpClientConfig, (axios, url, config) =>\n axios.get(url, config)\n );\n },\n post: (url, payload, httpClientConfig = axiosConfigs.authenticated) => {\n return axiosWrapper(url, httpClientConfig, (axios, url, config) =>\n axios.post(url, payload, config)\n );\n },\n put: (url, payload, httpClientConfig = axiosConfigs.authenticated) => {\n return axiosWrapper(url, httpClientConfig, (axios, url, config) =>\n axios.put(url, payload, config)\n );\n }\n };\n};\n\nconst trpcClient = endpoint => {\n const client = httpClient(`/api/${endpoint}`, false);\n const unpackResponse = ({ data }) => data;\n return {\n command: (url, payload, httpClientConfig) =>\n client\n .post(`/commands/${url}`, payload, httpClientConfig)\n .then(unpackResponse),\n query: (url, httpClientConfig) =>\n client.get(`/queries/${url}`, httpClientConfig).then(unpackResponse)\n };\n};\n\nexport const defaultClient = httpClient('');\nexport const touchWebClient = httpClient('/', true);\nexport const webApiClient = httpClient(ENDPOINTS.WEB_API);\nexport const cmsApiClient = httpClient(ENDPOINTS.CMS_API);\nexport const liveShoppingApiClient = httpClient(\n ENDPOINTS.LIVE_SHOPPING_PUBLIC_API\n);\nexport const marketingApiClient = httpClient(ENDPOINTS.MARKETING_PUBLIC_API);\nexport const memberIdentificationClient = trpcClient('member-identification');\nexport const translationOnDemandClient = trpcClient('translation-on-demand');\n","export default {\n TRADERA: 'https://www.tradera.com'\n};\n","import qs from 'qs';\nimport HOSTS from 'tradera-constants/hosts';\nimport initData from 'init-data';\nimport logger from 'packages/logger';\n\n// List of SPA paths for the regex match, without initial slash\nconst SPA_REGEX_PATHS = [\n 'search',\n 'campaign',\n 'charity',\n 'kategorier',\n 'profile\\\\/items',\n 'brand\\\\/.+',\n // Category\n '[a-z]+[\\\\w\\\\-]+[\\\\-|_]\\\\d+'\n];\nconst SPA_PATH_REGEX = new RegExp(\n `^(\\\\/en|\\\\/da|\\\\/de)?/(${SPA_REGEX_PATHS.join('|')})`\n);\nconst SUPPORTED_LANGUAGES = ['en', 'de', 'da'];\n\n/**\n * Returns language parameter from url\n * @param {*} url\n */\nconst getLanguagePrefixFromUrl = url => {\n const matches = url.match(/\\/([a-z][a-z])((\\/.*$)|$)/);\n\n if (matches === null) {\n return null;\n }\n\n const firstMatch = matches.find((match, index) => index > 0 && match);\n\n if (SUPPORTED_LANGUAGES.indexOf(firstMatch) !== -1) {\n return firstMatch;\n }\n\n return null;\n};\n\n/**\n * Format query params parsed from query string\n *\n * @param {object} queryParams\n * @returns {object}\n */\nconst formatQueryParams = queryParams => {\n const { categoryId, ...rest } = queryParams;\n const formattedQueryParams = rest;\n if (categoryId !== undefined) {\n formattedQueryParams.categoryId = parseInt(categoryId, 10);\n }\n return formattedQueryParams;\n};\n\n/**\n * Check if url is absolute\n *\n * @param {string} url\n * @returns {boolean}\n */\nconst isAbsoluteUrl = url => new RegExp('^(?:[a-z]+:)?//', 'i').test(url);\n\n/**\n * Tests if a given url or path is an SPA link or not\n *\n * @param {string} urlOrPath\n * @returns {boolean}\n */\nfunction isSpaLink(urlOrPath) {\n let pathname;\n if (/(^http)s?:\\/\\//i.test(urlOrPath)) {\n try {\n ({ pathname } = new URL(urlOrPath));\n } catch {\n return false;\n }\n } else {\n pathname = urlOrPath;\n }\n return SPA_PATH_REGEX.test(pathname);\n}\n\n/**\n * Takes an object and returns a new object without attribute properties\n * @param {object} queryParams\n * @returns {object}\n */\nconst stripAttributesFromQueryParameters = queryParams => {\n // Using object spread to exclude listed variables from 'rest'\n // eslint-disable-next-line no-unused-vars\n const { attributes, ...rest } = queryParams;\n return rest;\n};\n\n/**\n * Takes an object and returns a new object without pagination properties\n * @param {object} queryParams\n * @returns {object}\n */\nconst stripCategoryIdFromQueryParameters = queryParams => {\n // Using object spread to exclude listed variables from 'rest'\n // eslint-disable-next-line no-unused-vars\n const { categoryId, ...rest } = queryParams;\n return rest;\n};\n\n/**\n * Removes tradera base from a url, leaving path and query\n *\n * @param {string} url\n * @returns {string}\n */\nconst stripHost = url =>\n url.startsWith('http') ? url.replace(HOSTS.TRADERA, '') : url;\n\n/**\n * Takes an object and returns a new object without itm properties\n * Itm tags should no longer be used, so this method will then be obsolete\n * @param {object} queryParams\n * @returns {object}\n */\nconst stripItmFromQueryParameters = queryParams => {\n // Using object spread to exclude listed variables from 'rest'\n // eslint-disable-next-line no-unused-vars\n const { itm_source, itm_medium, ...rest } = queryParams;\n return rest;\n};\n\n/**\n * Takes an object and returns a new object without pagination properties\n * @param {object} queryParams\n * @returns {object}\n */\nconst stripPaginationFromQueryParameters = queryParams => {\n // Using object spread to exclude listed variables from 'rest'\n // eslint-disable-next-line no-unused-vars\n const { spage, paging, page, fe, ...rest } = queryParams;\n return rest;\n};\n\n/**\n * Takes an object and returns a new object without savedQueryName properties\n * @param {object} queryParams\n * @returns {object}\n */\nconst stripSavedQueryNameFromQueryParameters = queryParams => {\n // Using object spread to exclude listed variables from 'rest'\n // eslint-disable-next-line no-unused-vars\n const { savedQueryName, ...rest } = queryParams;\n return rest;\n};\n\n/**\n * Takes an url and adds tradera base url if it is not already an absolute url\n *\n * @param {string} relativeUrl\n * @returns {string}\n */\nconst toAbsoluteUrl = relativeUrl =>\n relativeUrl.startsWith('http')\n ? relativeUrl\n : `${HOSTS.TRADERA}${\n relativeUrl.startsWith('/') ? relativeUrl : '/' + relativeUrl\n }`;\n\n/**\n * From react router location object to absolute url string\n * @param {{pathname: string, search: string}} url\n * @returns {string}\n */\nconst toAbsoluteUrlFromObject = url =>\n toAbsoluteUrl(\n `${url.pathname ? url.pathname : ''}${url.search ? url.search : ''}`\n );\n\n/**\n * From URL to URL with language prefix\n * @param {*} url\n * @param {*} languageCodeIso2\n */\nconst toLocalizedUrl = (url, languageCodeIso2) => {\n if (url === null || url === undefined || url === '' || url === false) {\n return url;\n }\n\n const ignoredUrls = [initData.webApiUrl, '/api/webapi/'];\n const isIgnoredUrl = ignoredUrls.find(domain => url.indexOf(domain) !== -1);\n if (isIgnoredUrl) {\n return url;\n }\n\n if (!languageCodeIso2) {\n logger(`Missing language code for URL ${url}`);\n return url;\n }\n\n const isAbsolute = isAbsoluteUrl(url);\n\n const urlObject = isAbsolute\n ? new URL(url)\n : new URL(url, 'http://dummy.com');\n const origin = isAbsolute ? urlObject.origin : '';\n const localisedPathname = setLanguagePrefix(\n urlObject.pathname,\n languageCodeIso2\n );\n\n return `${origin}${localisedPathname}${urlObject.search}`;\n};\n\n/**\n * Creates query parameters object from search string\n * @param {string} search\n */\nconst toQueryParameters = search =>\n qs.parse(search, { ignoreQueryPrefix: true });\n\n/**\n * Removes the Tradera host from a url, making it relative\n * @param {string} url\n * @returns {string}\n */\nconst toRelativeTraderaUrl = url => {\n if (url.startsWith(HOSTS.TRADERA)) {\n return url.replace(HOSTS.TRADERA, '');\n } else {\n return url;\n }\n};\n\n/**\n * Creates search string from all properties in object\n * @param {object} queryParams\n * @param {{[addQueryPrefix]: bool, [encode]: bool, [skipNulls]: bool }}\n * @returns {string}\n */\nconst toSearchString = (\n queryParams,\n {\n addQueryPrefix = true,\n encode = true,\n skipNulls = true,\n arrayFormat = 'repeat' //qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }) ==> 'a=b&a=c'\n } = {}\n) =>\n qs.stringify(queryParams, {\n addQueryPrefix: addQueryPrefix,\n encode: encode,\n skipNulls: skipNulls,\n arrayFormat: arrayFormat\n });\n\nconst setLanguagePrefix = (path, languageCodeIso2) => {\n const languagePrefix = getLanguagePrefixFromUrl(path);\n const defaultLanguage = 'sv';\n\n if (languagePrefix) {\n if (languageCodeIso2 === defaultLanguage) {\n return path.replace(`/${languagePrefix}`, '');\n } else {\n return path.replace(languagePrefix, languageCodeIso2);\n }\n } else {\n if (languageCodeIso2 === defaultLanguage) {\n return path;\n } else {\n return `/${languageCodeIso2}${path}`;\n }\n }\n};\n\nconst getBackToHereRedirectUrl = () => {\n // Add random query parameter to force reload when redirecting to this url\n // and only the hash differs\n const queryParams = {\n ...qs.parse(location.search, { ignoreQueryPrefix: true }),\n forceRedirect: Math.round(Math.random() * 100000)\n };\n return (\n location.protocol +\n '//' +\n location.host +\n location.pathname +\n qs.stringify(queryParams, { addQueryPrefix: true })\n );\n};\n\nexport {\n SUPPORTED_LANGUAGES,\n getLanguagePrefixFromUrl,\n formatQueryParams,\n getBackToHereRedirectUrl,\n isAbsoluteUrl,\n isSpaLink,\n stripAttributesFromQueryParameters,\n stripCategoryIdFromQueryParameters,\n stripHost,\n stripItmFromQueryParameters,\n stripPaginationFromQueryParameters,\n stripSavedQueryNameFromQueryParameters,\n toAbsoluteUrl,\n toAbsoluteUrlFromObject,\n toLocalizedUrl,\n toQueryParameters,\n toRelativeTraderaUrl,\n toSearchString\n};\n","import dayjs from 'dayjs';\n\nfunction formatDuration(durationInSeconds, minuteBreakpoint = 60) {\n if (Number.isInteger(durationInSeconds)) {\n if (durationInSeconds > 24 * 60 * 60) return ''; // Show format from server\n\n if (durationInSeconds > 60 * 60)\n return `${Math.floor(\n durationInSeconds / 60 / 60\n )} tim ${Math.floor((durationInSeconds / 60) % 60)} min`;\n\n if (durationInSeconds > minuteBreakpoint)\n return `${Math.floor(durationInSeconds / 60)} min`;\n\n return `${durationInSeconds} s`;\n } else {\n return '';\n }\n}\n\nfunction formatStaticEndTime(endDateInput) {\n if (!endDateInput) return '';\n const endDate = dayjs(endDateInput);\n return endDate.format('D MMM HH:mm');\n}\n\nfunction formatEndDate(endDateInput, t, nowDateInput) {\n if (!endDateInput || !nowDateInput) return '';\n\n const endDate = dayjs(endDateInput);\n const now = dayjs(nowDateInput);\n if (endDate.isSameOrAfter(now.add(1, 'week'), 'day')) {\n return endDate.format('D MMM HH:mm');\n }\n if (endDate.isSameOrAfter(now.add(2, 'day'), 'day')) {\n return endDate.format('ddd HH:mm');\n }\n if (endDate.isSameOrAfter(now.add(1, 'day'))) {\n return `${t('vip_tomorrow')} ${endDate.format('HH:mm')}`;\n }\n if (endDate.isSameOrAfter(now.add(1, 'minute'))) {\n const hours = endDate.diff(now, 'hour');\n const minutes = endDate.diff(now, 'minute') % 60;\n const timeParts = [];\n if (hours > 0) {\n timeParts.push(t('vip_hours', { count: hours }));\n }\n if (minutes > 0) {\n timeParts.push(t('vip_minutes', { count: minutes }));\n }\n return timeParts.join(' ');\n }\n if (endDate.isAfter(now)) {\n return t('vip_less_than_1_min_left');\n }\n return t('vip_ended');\n}\n\nfunction formatNumberWithSeparators(number, separator = '\\u2006') {\n return number\n .toString()\n .replace(/(\\d)(?=(\\d{3})+(?!\\d))/g, '$1' + separator);\n}\n\n// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString\nfunction toLocaleStringSupportsLocales() {\n try {\n Number(0).toLocaleString('i');\n } catch (e) {\n return e.name === 'RangeError';\n }\n return false;\n}\n\n// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString\nfunction toLocaleStringSupportsOptions() {\n return !!(\n typeof Intl === 'object' &&\n Intl &&\n typeof Intl.NumberFormat === 'function'\n );\n}\n\nconst isLocaleFormattingSupportedInBrowser =\n toLocaleStringSupportsLocales() && toLocaleStringSupportsOptions();\n\nfunction formatSellerDsrAverage(value, locale = 'sv-SE') {\n return value?.toLocaleString(locale, {\n minimumFractionDigits: 1,\n maximumFractionDigits: 1\n });\n}\n\nfunction formatPrice(price, locale = 'sv-SE', options = {}) {\n if (!isLocaleFormattingSupportedInBrowser) {\n return `${typeof price === 'number' ? price : parseInt(price)} ${\n locale.startsWith('sv') ? 'kr' : 'SEK'\n }`;\n }\n let formattedPrice = typeof price !== 'number' ? parseInt(price) : price;\n const opts = {\n style: 'currency',\n currency: 'SEK',\n currencyDisplay: 'symbol',\n useGrouping: false,\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n ...options\n };\n formattedPrice = formattedPrice.toLocaleString(locale, opts);\n formattedPrice = formatNumberWithSeparators(formattedPrice);\n return formattedPrice;\n}\n\nfunction formatDateWithDayOfWeek(dateString, locale) {\n if (!isLocaleFormattingSupportedInBrowser) {\n return dateString;\n }\n\n var options = {\n weekday: 'long',\n year: undefined,\n month: 'long',\n day: 'numeric'\n };\n return new Intl.DateTimeFormat(locale, options).format(\n Date.parse(dateString)\n );\n}\n\nexport {\n formatDuration,\n formatStaticEndTime,\n formatEndDate,\n formatNumberWithSeparators,\n formatPrice,\n formatSellerDsrAverage,\n formatDateWithDayOfWeek\n};\n","/**\n * A queue with a that handled max age (ttl) for messages.\n * @returns\n */\nexport const createQueue = () => {\n const items = [];\n const dayInMinutes = 60 * 24;\n const add = (item, ttlInMinutes = dayInMinutes) => {\n const timeStamp = Date.now();\n items.push({ item, ttlInMinutes, timeStamp });\n };\n const isAlive = ({ ttlInMinutes, timeStamp }) => {\n return timeStamp + ttlInMinutes * 60 * 1000 >= Date.now();\n };\n let inProgress = null;\n return {\n add,\n next: () => {\n let itemData = items.shift();\n while (itemData && !isAlive(itemData)) {\n itemData = items.shift();\n }\n inProgress = itemData?.item || null;\n return inProgress;\n },\n notifyDone: () => {\n inProgress = null;\n },\n isInProgress: () => inProgress !== null,\n getLength: () => items.length\n };\n};\n","// extracted by mini-css-extract-plugin\nexport default {\"item-toast\":\"item-toast--QaLFk\",\"itemToast\":\"item-toast--QaLFk\",\"item-toast-image\":\"item-toast-image--i_l4w\",\"itemToastImage\":\"item-toast-image--i_l4w\"};","import React from 'react';\nimport { formatNumberWithSeparators } from 'tradera-utils/format';\nimport ALink from 'tradera-components/alink/alink';\nimport { useTranslator, useUrlLocalizer } from 'tradera-lang/translate';\nimport styles from './item-toast.module.scss';\n\nexport const ItemToast = ({\n imageUrl,\n itemUrl,\n shortDescription,\n type,\n eventData\n}) => {\n const { toLocalizedUrl } = useUrlLocalizer();\n\n return (\n \n \n

\n
\n
\n \n );\n};\n\nconst ToastMessage = ({ type, shortDescription, eventData }) => {\n const { t } = useTranslator();\n let message;\n switch (type) {\n case 'ItemOutbidded':\n message = t('siteWideNotifications_itemOutbidded', {\n newLeadingBidAmount: formatNumberWithSeparators(\n eventData.newLeadingBidAmount\n ),\n shortDescription\n });\n break;\n case 'ItemFirstBid':\n message = t('siteWideNotifications_itemFirstBid', {\n shortDescription\n });\n break;\n case 'ItemSold':\n message = t('siteWideNotifications_itemSold', {\n price: formatNumberWithSeparators(eventData.price),\n shortDescription\n });\n break;\n case 'ItemWon':\n message = t('siteWideNotifications_itemWon', {\n price: formatNumberWithSeparators(eventData.price),\n shortDescription\n });\n break;\n case 'ItemPaid':\n message = t('siteWideNotifications_itemPaid', {\n shortDescription\n });\n break;\n case 'ItemWishListReminder':\n message = t('siteWideNotifications_itemWishListReminder', {\n shortDescription,\n timeLeftMinutes: eventData.timeLeftMinutes\n });\n }\n return {message}
;\n};\n","import React from 'react';\nimport { toast } from 'react-toastify';\n\nimport { ItemToast } from 'tradera-components/toasts/item-toast';\nimport { webApiClient } from '../utils/http';\nimport { createQueue } from './toast-queue';\n\nconst queuedToasts = createQueue();\n\nexport const ToastTestButton = () => (\n \n);\n\nconst openNextToast = async () => {\n if (queuedToasts.isInProgress()) {\n return;\n }\n const nextItem = queuedToasts.next();\n if (nextItem) {\n try {\n const response = await webApiClient.get(\n `/browse/item-basic-info/${nextItem.eventData.itemId}`\n );\n const { imageUrl, itemUrl, shortDescription } = response.data.item;\n const queueLength = queuedToasts.getLength();\n toast(\n React.createElement(ItemToast, {\n imageUrl,\n itemUrl,\n shortDescription,\n type: nextItem.type,\n eventData: nextItem.eventData\n }),\n {\n autoClose: Math.max(2, 5 - queueLength) * 1000,\n onClose: () => {\n queuedToasts.notifyDone();\n openNextToast();\n }\n }\n );\n } catch (e) {\n queuedToasts.notifyDone();\n openNextToast();\n throw e;\n }\n }\n};\n\nconst handleNotification = async (type, eventData, ttlInMinutes = 10) => {\n if (document.visibilityState !== 'visible') {\n // We don't want to show messages if page is not visible. If we do they will queue up!\n return;\n }\n\n queuedToasts.add({ type, eventData }, ttlInMinutes);\n openNextToast();\n};\n\nexport const showItemOutbiddedToast = (itemId, newLeadingBidAmount) =>\n handleNotification('ItemOutbidded', {\n itemId,\n newLeadingBidAmount\n });\n\nexport const showItemFirstBidToast = itemId =>\n handleNotification('ItemFirstBid', { itemId });\n\nexport const showItemSoldToast = (itemId, price) =>\n handleNotification('ItemSold', { itemId, price });\n\nexport const showItemWonToast = (itemId, price) =>\n handleNotification('ItemWon', { itemId, price });\n\nexport const showItemPaidToast = itemId =>\n handleNotification('ItemPaid', { itemId });\n\nexport const showItemWishListReminderToast = (itemId, timeLeftMinutes) =>\n handleNotification(\n 'ItemWishListReminder',\n { itemId, timeLeftMinutes },\n timeLeftMinutes > 10 ? 10 : 2\n );\n","import {\n showItemFirstBidToast,\n showItemOutbiddedToast,\n showItemPaidToast,\n showItemSoldToast,\n showItemWishListReminderToast,\n showItemWonToast\n} from './toasts';\nimport axios from 'axios';\nimport ENDPOINTS from 'tradera-constants/endpoints';\nimport { getGlobalSocket } from './global-socket';\n\nconst refreshLoginState = async socket => {\n try {\n const response = await axios.get(\n ENDPOINTS.TOUCHWEB_URL + 'login/state'\n );\n\n if (!response.data?.isLoggedIn) {\n return;\n }\n\n socket.disconnect();\n socket.connect();\n } catch {\n // Could not get token.\n }\n};\n\nexport const bootSiteWideNotifications = ({ socketUrl, joinMemberRoom }) => {\n if (!joinMemberRoom) {\n return;\n }\n\n const socket = getGlobalSocket(socketUrl);\n let isRetry = false;\n socket.on('JoinMemberRoom', async ({ success }) => {\n // To avoid infinite loop\n if (success || isRetry) {\n isRetry = false;\n return;\n }\n\n isRetry = true;\n await refreshLoginState(socket);\n });\n socket.addEventListener('MemberItemOutbidded', data =>\n showItemOutbiddedToast(data.ItemId, data.NewLeadingBidAmount)\n );\n socket.addEventListener('MemberItemFirstBid', data =>\n showItemFirstBidToast(data.ItemId)\n );\n socket.addEventListener('MemberItemSold', data =>\n showItemSoldToast(data.ItemId, data.Price)\n );\n socket.addEventListener('MemberItemWon', data =>\n showItemWonToast(data.ItemId, data.Price)\n );\n socket.addEventListener('MemberItemPaid', data =>\n showItemPaidToast(data.ItemId)\n );\n socket.addEventListener('MemberItemWishListReminder', data =>\n showItemWishListReminderToast(data.ItemId, data.TimeLeftMinutes)\n );\n socket.join('member');\n};\n","import 'core-js/modules/es.promise.finally';\nimport 'core-js/modules/es.array.iterator';\nimport 'intersection-observer';\nimport 'custom-event-polyfill';\nimport 'whatwg-fetch';\n\nimport initData from 'init-data';\nimport {\n handleModuleError,\n isSpaModule,\n loadModule,\n loadSpaModule,\n runModule\n} from 'utils/modules';\nimport { bootLanguages } from 'tradera-lang/boot-languages';\nimport gtm from 'static/script/app/ui/google-tagmanager-service';\nimport { bootSiteWideNotifications } from 'tradera-services/boot-site-wide-notifications';\nimport { getServerDate } from 'tradera-utils/server-date';\nimport { configureDayjs } from 'tradera-apps/tradera/configure-dayjs';\n\nbootLanguages();\nconfigureDayjs();\ngetServerDate();\ngtm.loadGtmScript();\n\nif (initData) {\n if (initData.featureSwitches['site-wide-notifications']) {\n bootSiteWideNotifications({\n socketUrl: initData.webLiveUrl,\n joinMemberRoom: !!initData.memberId\n });\n }\n\n const module = initData.module.split('/')[4];\n let moduleLoader;\n if (isSpaModule(module, initData)) {\n moduleLoader = loadSpaModule(initData);\n } else {\n moduleLoader = import('./init-module')\n .then(initModule => initModule.default(initData))\n .then(() => loadModule(module, initData))\n .then(loadedModule => runModule(loadedModule, initData));\n }\n moduleLoader\n .then(() => {\n window.document.body.setAttribute('data-module-loaded', 'true');\n return;\n })\n .catch(handleModuleError);\n}\n","import dayjs from 'dayjs';\nimport isBetween from 'dayjs/plugin/isBetween';\nimport isSameOrAfter from 'dayjs/plugin/isSameOrAfter';\nimport { getCurrentLanguage } from 'tradera-lang/boot-languages';\n\nexport const configureDayjs = () => {\n dayjs.locale(getCurrentLanguage());\n dayjs.extend(isBetween);\n dayjs.extend(isSameOrAfter);\n};\n","import axios from 'axios';\nimport { getCurrentLanguage } from 'tradera-lang/boot-languages';\nimport { toLocalizedUrl } from 'tradera-utils/url';\n\nconst timeDiffInMs = start => {\n return Date.now() - start;\n};\n\nconst queryServerTime = async retryCount => {\n const latencyLimit = 2000;\n const maxRetries = 2;\n const requestStart = Date.now();\n const {\n data: { currentTime }\n } = await axios.get(\n toLocalizedUrl(\n '/api/webapi/discover/server-time.json',\n getCurrentLanguage()\n )\n );\n const latency = timeDiffInMs(requestStart);\n\n if (latency < latencyLimit) {\n return { currentTime: Date.parse(currentTime), latency };\n } else if (retryCount < maxRetries) {\n return queryServerTime(retryCount + 1);\n } else {\n return null;\n }\n};\n\n/**\n * Requests server time and returns\n * { currentTime, latency }\n */\nexport const getServerTime = async () => {\n return await queryServerTime(0);\n};\n","import { getServerTime } from 'tradera-utils/time-api';\n\nlet _minServerCheckInterval = 1000 * 60 * 5;\nlet _serverDiff = 0;\nlet _didGetServerResponse = false;\nlet _lastCheckAtMs = null;\n\nconst updateServerDiff = async () => {\n _lastCheckAtMs = Date.now();\n const serverTimeObject = await getServerTime();\n if (serverTimeObject) {\n _didGetServerResponse = true;\n // We add the whole latency even though it may give a later\n // time than in reality since a later time gives less time\n // left until auctions expire. This is better than showing\n // too much time left.\n const timeNowOnServer = new Date(\n serverTimeObject.currentTime + serverTimeObject.latency\n );\n _serverDiff = timeNowOnServer.getTime() - Date.now();\n }\n};\n\nconst shouldCheckServer = () =>\n _lastCheckAtMs === null ||\n Date.now() - _lastCheckAtMs >= _minServerCheckInterval;\n\nlet _initialPromise = null;\n\n/**\n * Gets the date on the server and shall be used for calculating auction time left.\n * @returns The date or null if server did not respond at least once.\n */\nexport const getServerDate = async () => {\n if (shouldCheckServer()) {\n let promise = updateServerDiff();\n if (!_didGetServerResponse) {\n _initialPromise = promise;\n }\n }\n\n if (_initialPromise) {\n try {\n await _initialPromise;\n } catch {\n // Don't throw any errors.\n }\n _initialPromise = null;\n }\n\n return _didGetServerResponse ? new Date(Date.now() + _serverDiff) : null;\n};\n\nexport const resetForTesting = () => {\n _minServerCheckInterval = 0;\n _didGetServerResponse = null;\n};\n","/**\n * @returns initData as JSON;\n * Default\n */\nconst initData = function() {\n if (!window.initData) {\n const initDataEL = document.getElementById('init-data');\n if (initDataEL) {\n const data = initDataEL.getAttribute('data-init-data');\n const parsed = JSON.parse(data);\n return parsed;\n } else {\n return null;\n }\n } else {\n return window.initData;\n }\n};\n\nexport const getInitData = initData;\nexport default new initData();\n","import { toLocalizedUrl } from 'tradera-utils/url';\n\nexport const toLocalizedRiotUrl = url => toLocalizedUrl(url, getLanguage());\n\nlet language;\nexport const getLanguage = () => {\n if (language === '' || language === null || language === undefined) {\n language = document.querySelector('html').getAttribute('lang');\n }\n\n return language;\n};\n","import logger from 'logger';\n\nfunction isSpaModule(module, initData) {\n const { isSinglePageApp } = initData;\n switch (module) {\n case 'start-page':\n case 'brand':\n case 'brand-list':\n case 'category-list':\n case 'endless-recommendation':\n case 'favourite-sellers':\n case 'landing':\n case 'live-shopping-event-list-page':\n case 'report-item':\n case 'profile':\n case 'verify-bankid':\n case 'tradera-shop':\n case 'category':\n case 'custom-results':\n case 'search-results':\n return true;\n\n default:\n return isSinglePageApp;\n }\n}\n\nasync function loadSpaModule(initData) {\n const module = await import(\n /* webpackChunkName: \"tradera\" */ '../../../../frontend/apps/tradera/'\n );\n return module.default(initData);\n}\n\nasync function loadModule(module) {\n switch (module) {\n // Fallback modules for when SPA is toggled off\n // TODO: Remove when fully incorporated in SPA\n case 'start-page':\n case 'brand':\n case 'brand-list':\n case 'category-list':\n case 'landing':\n case 'live-shopping-event-list-page':\n case 'order-checkout':\n case 'verify-bankid':\n case 'profile':\n case 'cart':\n case 'upi':\n case 'inr':\n case 'cause':\n case 'causes':\n case 'causes-info':\n return await import(\n /* webpackChunkName: \"tradera\" */ '../../../../frontend/apps/tradera/'\n );\n\n // Non-SPA modules\n case 'basic':\n return await import(\n /* webpackChunkName: \"basic\" */ '../app/pages/basic'\n );\n case 'bidding':\n return await import(\n /* webpackChunkName: \"bidding\" */ '../app/pages/bidding'\n );\n case 'bin-form':\n return await import(\n /* webpackChunkName: \"bin-form\" */ '../app/pages/bin-form'\n );\n case 'cart-checkout':\n return await import(\n /* webpackChunkName: \"cart-checkout\" */ '../app/pages/cart-checkout'\n );\n case 'checkout-select-payment':\n return await import(\n /* webpackChunkName: \"checkout-select-payment\" */ '../app/pages/checkout-select-payment'\n );\n case 'checkout2':\n return await import(\n /* webpackChunkName: \"checkout2\" */ '../app/pages/checkout2'\n );\n case 'detailed-search':\n return await import(\n /* webpackChunkName: \"detailed-search\" */ '../app/pages/detailed-search'\n );\n case 'image-search':\n return await import(\n /* webpackChunkName: \"image-search\" */ 'tradera-apps/image-search'\n );\n case 'messages':\n return await import(\n /* webpackChunkName: \"messages\" */ '../app/pages/messages'\n );\n case 'messaging':\n return await import(\n /* webpackChunkName: \"messaging-iframe\" */ '../app/pages/messaging'\n );\n default:\n return await import(\n /* webpackChunkName: \"basic\" */ '../app/pages/basic'\n );\n }\n}\n\nfunction runModule(module, initData = {}) {\n if (!module.default) {\n //eslint-disable-next-line\n console.error(`Cannot run module \"${module}\" without exported default`);\n }\n return module.default(initData);\n}\n\nconst handleModuleError = error => logger(error);\n\nexport { isSpaModule, loadSpaModule, loadModule, runModule, handleModuleError };\n","import { createSlice } from '@reduxjs/toolkit';\n\nexport const initialState = {};\n\nconst slice = createSlice({\n name: 'environment',\n initialState,\n reducers: {\n setEnvironmentHash: (state, { payload }) => {\n state.environmentHash = payload;\n },\n setIsSpaNavigationEnabled: (state, { payload }) => {\n state.isSpaNavigationEnabled = payload;\n }\n }\n});\n\nexport const { setEnvironmentHash, setIsSpaNavigationEnabled } = slice.actions;\nexport const reducer = slice.reducer;\n","import axios from 'axios';\n\nimport { logger } from 'packages/index';\nimport ENDPOINTS from 'tradera-constants/endpoints';\n\n/**\n * Standardized api error codes\n */\nconst API_ERRORS = {\n IGNORE_ME: 'IGNORE_ME',\n ABORTED: 'ABORTED',\n CANCELLED: 'CANCELLED',\n NETWORK: 'NETWORK',\n TIMEOUT: 'TIMEOUT',\n VERSION_MISMATCH: 'VERSION_MISMATCH',\n LOGGED_OUT: 'LOGGED_OUT'\n};\n\nconst defaultJsonRequestHeaders = {\n // Force json response\n Accept: 'application/json',\n // For WebAPI and RequiresAuthorization to handle ajax request\n 'X-Requested-With': 'XMLHttpRequest'\n};\n\n/**\n * Standard Axios configs\n */\nconst axiosConfigs = {\n // Requests to endpoints with authentication\n authenticated: {\n // Send auth cookies\n withCredentials: true,\n headers: defaultJsonRequestHeaders\n },\n notAuthenticated: {\n // Dont send auth cookies\n withCredentials: false,\n headers: defaultJsonRequestHeaders\n }\n};\n\nconst isMissingAuthToken = responseString => {\n try {\n const responseObject = JSON.parse(responseString);\n const isMissing =\n responseObject.responseStatus.errorCode === 'MissingAuthToken';\n return isMissing;\n } catch {\n return false;\n }\n};\n\nconst isUnauthorized = statusCode => statusCode === 401;\n\nconst addAntiCacheParam = url => {\n const antiCacheRegExp = /([?&]_=)[^&]*/;\n return antiCacheRegExp.test(url)\n ? url.replace(antiCacheRegExp, '$1' + new Date().getTime())\n : url + (/\\?/.test(url) ? '&' : '?') + '_=' + new Date().getTime();\n};\n\nconst submitOriginalRequest = async error =>\n axios({\n ...error.config,\n url: addAntiCacheParam(error.config.url)\n });\n\nconst handleMissingAuthToken = async error => {\n const refreshAccessToken = async () =>\n axios.get(ENDPOINTS.TOUCHWEB_URL + 'login/state');\n const handleErrorAfterRefresh = async errorAfterRefreshToken => {\n if (isUnauthorized(errorAfterRefreshToken.request?.status)) {\n error.message = API_ERRORS.LOGGED_OUT;\n }\n return Promise.reject(error);\n };\n return refreshAccessToken()\n .then(() => submitOriginalRequest(error))\n .catch(handleErrorAfterRefresh);\n};\n\nconst handleUnauthorized = async error => {\n const checkLoginState = async () =>\n axios.get(ENDPOINTS.TOUCHWEB_URL + 'login/state');\n return checkLoginState().then(response => {\n const isLoggedIn = response.data?.isLoggedIn;\n if (isLoggedIn) {\n return submitOriginalRequest(error);\n }\n error.message = API_ERRORS.LOGGED_OUT;\n // eslint-disable-next-line promise/no-return-wrap\n return Promise.reject(error);\n });\n};\n\nconst errorResponseInterceptor = error => {\n if (isMissingAuthToken(error.request?.response)) {\n return handleMissingAuthToken(error);\n } else if (isUnauthorized(error.request?.status)) {\n return handleUnauthorized(error);\n }\n return Promise.reject(error);\n};\n\n/**\n * Create Axios instance or decorate existing instance with interceptor for expired token responses\n *\n * @param {AxiosInstance} [axiosInstance]\n * @returns {AxiosInstance}\n */\nfunction axiosWithTokenRefresh(axiosInstance) {\n let instance;\n if (axiosInstance === undefined) {\n instance = axios.create();\n } else {\n instance = axiosInstance;\n }\n instance.interceptors.response.use(\n response => response,\n errorResponseInterceptor\n );\n return instance;\n}\n\nconst cancelTokens = {};\n\n/**\n * Create new or return existing cancellation function\n *\n * Usage:\n * const { cancel, cancelToken } = utilizeCancelToken('tokenId')\n * if (cancel) cancel();\n * axios.get('http://api.com/...', { cancelToken });\n *\n * @param {string} tokenId - A string ID shared between requests that cancel together\n * @returns {{ cancel: function, cancelToken: function }}\n */\nfunction utilizeCancelToken(tokenId) {\n let cancel;\n if (tokenId in cancelTokens) {\n cancel = cancelTokens[tokenId].cancel;\n }\n cancelTokens[tokenId] = axios.CancelToken.source();\n return {\n cancel,\n cancelToken: cancelTokens[tokenId].token\n };\n}\n\n/**\n * Check response version and throw error if different from current\n *\n * @param {string} version\n * @return {function(*): object|void}\n */\nfunction checkResponseVersion(version = '12.0.0') {\n return response => {\n if (\n response.headers &&\n response.headers['X-Tradera-Version'] &&\n response.headers['X-Tradera-Version'] !== version\n ) {\n throw new Error(API_ERRORS.VERSION_MISMATCH);\n } else {\n return response;\n }\n };\n}\n\n/**\n * Checks redirect response for logged out user\n * This is an old solution. New solutions return a 401 response instead (see handleError).\n * Requires Axios config to include { withCredentials: true }\n *\n * @returns {Function}\n */\nfunction checkResponseLoggedOut() {\n return response => {\n if (\n response.data &&\n typeof response.data === 'string' &&\n response.data.includes('Logga in')\n ) {\n throw new Error(API_ERRORS.LOGGED_OUT);\n } else {\n return response;\n }\n };\n}\n\n/**\n * Final standardized formatting of an api response\n *\n * @returns { function(*): { data: *, status: integer }}\n */\nfunction finalizeResponse() {\n return response => {\n const { data, status } = response;\n return {\n data,\n status\n };\n };\n}\n\n/**\n * Common network request error handling\n *\n * @param {Object.} statusHandlers - { code: message }\n * @returns {function(*=): Promise}\n */\nfunction handleError(statusHandlers = {}) {\n return error => {\n let status = error.response && error.response.status;\n let message = error.message ? error.message : error.toString();\n if (axios.isCancel(error)) {\n error.message = API_ERRORS.CANCELLED;\n } else if (message.includes('timeout') || status === 408) {\n error.message = API_ERRORS.TIMEOUT;\n } else if (message.includes('Network')) {\n error.message = API_ERRORS.NETWORK;\n } else if (message.includes('Request aborted')) {\n error.message = API_ERRORS.ABORTED;\n } else if (status === 401) {\n error.message = API_ERRORS.LOGGED_OUT;\n } else if (status in statusHandlers) {\n error.message = statusHandlers[status];\n }\n throw error;\n };\n}\n\nfunction reloadOnUnauthorized(error) {\n switch (error.message) {\n case API_ERRORS.LOGGED_OUT:\n window.location.reload();\n break;\n default:\n throw error;\n }\n}\n\nfunction logError(error) {\n switch (error.message) {\n case API_ERRORS.IGNORE_ME:\n case API_ERRORS.CANCELLED:\n case API_ERRORS.NETWORK:\n case API_ERRORS.TIMEOUT:\n break;\n default:\n logger(error);\n break;\n }\n}\n\nexport {\n addAntiCacheParam,\n API_ERRORS,\n axiosConfigs,\n axiosWithTokenRefresh,\n checkResponseVersion,\n checkResponseLoggedOut,\n defaultJsonRequestHeaders,\n errorResponseInterceptor,\n finalizeResponse,\n handleError,\n logError,\n reloadOnUnauthorized,\n utilizeCancelToken\n};\n","import { SocketIoChannel } from 'tradera-services/socket-io-channel';\n\nlet globalSocket = null;\n\nexport const getGlobalSocket = socketUrl => {\n if (!globalSocket) {\n globalSocket = new SocketIoChannel(socketUrl, true);\n }\n return globalSocket;\n};\n","import axios from 'axios';\nimport { getCurrentLanguage } from 'tradera-lang/boot-languages';\nimport { toLocalizedUrl } from 'tradera-utils/url';\nimport { setEnvironmentHash, setIsSpaNavigationEnabled } from './reducer';\n\nexport const updateEnvironmentHash = () => async (dispatch, getState) => {\n const url = toLocalizedUrl('/ping', getCurrentLanguage());\n const response = await axios.get(url);\n const environmentHash = response.headers['x-tradera-environment'];\n const current = getState().environment.environmentHash;\n if (environmentHash !== current) {\n dispatch(setEnvironmentHash(environmentHash));\n dispatch(setIsSpaNavigationEnabled(false));\n }\n};\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { Link } from 'react-router-dom';\nimport { updateEnvironmentHash } from 'tradera-state/environment/actions';\n\nconst ALink = ({\n useLink,\n href,\n children,\n onClick: givenOnClick,\n ...otherProps\n}) => {\n const dispatch = useDispatch();\n const isSpaNavigationEnabled = useSelector(\n state => state.environment.isSpaNavigationEnabled\n );\n if (isSpaNavigationEnabled && useLink) {\n // Strip away origin for local links\n let to = href;\n if (href?.startsWith(location.origin)) {\n const { pathname, search } = new URL(href);\n to = pathname + search;\n }\n return (\n {\n dispatch(updateEnvironmentHash());\n if (givenOnClick) givenOnClick(evt);\n }}>\n {children}\n \n );\n } else {\n return (\n \n {children}\n \n );\n }\n};\n\nALink.propTypes = {\n useLink: PropTypes.bool,\n href: PropTypes.string.isRequired,\n children: PropTypes.node.isRequired,\n onClick: PropTypes.func\n};\n\nALink.defaultProps = {\n useLink: false,\n onClick: null\n};\n\nexport default ALink;\n","export const isPrerender = userAgent =>\n userAgent.indexOf('Prerender (+https://github.com/prerender/prerender)') >\n -1;\n","/* eslint-disable */ /**\n OBSOLETE - use google tag manager service instead:\n src\\EbaySweden.TouchWeb\\static\\script\\app\\ui\\google-tagmanager-service.js\n\n\n * Ported from Applications/TouchWeb/src/EbaySweden.TouchWeb/static/script/app/ui/layout/google-tagmanager.js\n * Best way to import this module is `import * as Analytics from 'analytics'`\n */\n\nimport * as Sentry from '@sentry/browser';\n\nexport const pushToDataLayer = payload => {\n window.dataLayer = window.dataLayer || [];\n window.dataLayer.push(payload);\n};\nexport const trackPageView = () =>\n window.ga\n ? ga('send', 'pageview', location.pathname)\n : pushToDataLayer({ event: 'trackPageview' });\nexport const isNonInteractive = analyticsData =>\n analyticsData.userTriggered === undefined\n ? true\n : !analyticsData.userTriggered;\n/**\n * trackTiming\n * @param {*} category\n * @param {*} variable\n * @param {*} value\n * @param {*} label\n */\nexport const trackTiming = (category, variable, value, label = '') =>\n window.ga ? ga('send', 'timing', category, variable, value, label) : false;\n\n/**\n * Track Analytics Event\n */\nexport const trackEvent = analyticsData => {\n if (!analyticsData) {\n return;\n }\n pushToDataLayer({\n event: 'trackEvent',\n eventCategory: analyticsData.category || '',\n eventAction: analyticsData.action || '',\n eventLabel: analyticsData.label || '',\n eventValue: analyticsData.value || '0',\n eventNonInteractive: isNonInteractive(analyticsData),\n hitCallback: analyticsData.hitCallback || []\n });\n\n Sentry.addBreadcrumb({\n type: 'default',\n level: Sentry.Severity.Info,\n category: isNonInteractive(analyticsData) ? 'tracking' : 'ui-action',\n message: 'Analytics Event',\n data: analyticsData\n });\n};\n\n// Export object for Sinon stubbing\nexport default {\n pushToDataLayer,\n trackEvent,\n trackPageView,\n trackTiming\n};\n","/**\n *\n * # track events:\n * import GtmService from 'static/script/app/ui/google-tagmanager-service';\n * GtmService.trackGtmEvent(\"zorro\", { marvel: false, black: true })\n *\n *\n *\n */\n\nimport * as Sentry from '@sentry/browser';\nimport initData from '../../packages/init-data';\n\n/**\n * SPA page view tracking becomes enabled after first\n * page view tracking which happens after the first\n * page is loaded from server.\n * This prevents reset of data layer after a SPA route has\n * changed (happens late after full page load) and prevents\n * duplicated trackPageView events.\n */\nlet spaPageViewTrackingEnabled = false;\n\nclass GoogleTagManagerService {\n loadGtmScript() {\n this._newPageFromServer();\n\n const accountId = 'GTM-5TMB2D';\n (function(w, d, s, l, i) {\n w[l] = w[l] || [];\n w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });\n var f = d.getElementsByTagName(s)[0],\n j = d.createElement(s),\n dl = l != 'dataLayer' ? '&l=' + l : '';\n j.async = true;\n j.src = '//www.googletagmanager.com/gtm.js?id=' + i + dl;\n f.parentNode.insertBefore(j, f);\n })(window, document, 'script', 'dataLayer', accountId);\n }\n\n push(payload) {\n window.dataLayer = window.dataLayer || [];\n window.dataLayer.push(payload);\n }\n\n _getDatalayerObject() {\n let output = {};\n if (window.dataLayer) {\n for (let entry of window.dataLayer) {\n output = { ...output, ...entry };\n }\n }\n return output;\n }\n\n /**\n * destroy datalayer from previous loading. this is really only useful in spa pages, it's backwards compatible so it doesnt do any harm on old pages\n */\n _reset() {\n if (!window.dataLayer) {\n return;\n }\n\n let data = this._getDatalayerObject();\n for (let key of Object.keys(data)) {\n data[key] = undefined;\n }\n window.dataLayer.push({ ...data, event: 'reset' });\n }\n\n newSpaPage(pageType) {\n if (!spaPageViewTrackingEnabled) {\n return;\n }\n this._reset();\n this._pushInitialDataLayer();\n this.push({ event: 'pageType', 'page.pageType': pageType });\n }\n\n _newPageFromServer() {\n this._pushInitialDataLayer();\n // ------------------------------------------------\n // backwards compatibility\n // get old datalayer info and push it in\n if (window.legacyDataLayer) {\n for (let entry of window.legacyDataLayer) {\n window.dataLayer.push({\n event: 'legacyDataLayer',\n ...entry\n });\n }\n }\n }\n\n _buildFromInitData() {\n return {\n memberId: initData.memberId || 0,\n userLanguage: initData.languageCodeIso2,\n memberEmail: initData.isLoggedIn ? initData.memberEmail : '',\n memberHashedEmail: initData.isLoggedIn\n ? initData.memberEmailSha256\n : '',\n 'criteo.hashedEmail': initData.isLoggedIn\n ? initData.memberEmailMd5\n : '',\n memberFirstName: initData.isLoggedIn\n ? initData.memberFirstName\n : '',\n memberLastName: initData.isLoggedIn ? initData.memberLastName : '',\n memberCountry: initData.isLoggedIn ? initData.memberCountry : '',\n loginState: initData.isLoggedIn ? 'logged in' : 'not logged in',\n isNotInIframe: window.self === window.top,\n 'blueshift.event-api-key': initData.blueshiftEventApiKey,\n isSinglePageApp: initData.isSinglePageApp,\n isNativeAppContext: initData.isNativeAppContext,\n isQuantcastConsentEnabled:\n initData.featureSwitches['quantcast-consent'],\n isDigitalAudienceTrackingEnabled:\n initData.featureSwitches['digital-audience-tracking'],\n quantcastSite: initData.quantcastSite\n };\n }\n\n _pushInitialDataLayer() {\n // init datalayer\n let initialDataLayer = this._buildFromInitData();\n\n // add split tests to datalayer\n if (initData.splitTestGroups) {\n for (let [key, value] of Object.entries(initData.splitTestGroups)) {\n initialDataLayer[`splittest_${key}`] = value;\n }\n }\n window.dataLayer = window.dataLayer || [];\n window.dataLayer.push({\n ...initialDataLayer,\n event: 'initialDataLayer'\n });\n }\n\n /**\n * tracks a google analytics event\n * @param {string} category ga category\n * @param {string} action ga action what happens, ie: \"Filter box - open/close\"\n * @param {string} label ga label what the value of the action was, ie \"close\"\n * @param {integer} [value] ga interger value of the action.\n */\n trackAction(category, action, label, value = 0, nonInteractive = false) {\n this.push({\n event: 'trackEvent',\n eventCategory: category || '',\n eventAction: action || '',\n eventLabel: label || '',\n eventValue: value || '0',\n eventNonInteractive: nonInteractive\n });\n\n Sentry.addBreadcrumb({\n type: 'default',\n level: Sentry.Severity.Info,\n category: nonInteractive ? 'tracking' : 'ui-action',\n message: 'Analytics Event',\n data: {\n category,\n action,\n label,\n value\n }\n });\n }\n\n /**\n * google tag manager event. Note: if you want to send google analytics events use trackAction instead\n * @param {string} eventName\n * @param {object} [event] data\n */\n trackGtmEvent(eventName, data = {}) {\n this.push({\n event: eventName,\n ...data\n });\n }\n\n /**\n * Track a pageview. Use this script in SPA's to make sure that analytics gets pageview information.\n * This creates a virtual page view since google analytics by default doesn't track changes to url via\n * push state.\n */\n trackPageView() {\n this.trackGtmEvent('trackPageview');\n spaPageViewTrackingEnabled = true;\n }\n\n /**\n *\n * @param {string} category\n * @param {string} action\n * @param {string} label\n * @param {string} callback\n * @param {} value\n */\n trackLinkClickAndCallback(category, action, label, callback, value = 0) {\n this.push({\n event: 'trackEvent',\n eventCategory: category || '',\n eventAction: action || '',\n eventLabel: label || '',\n eventValue: value || '0',\n eventNonInteractive: false,\n eventCallback: callback // part of google tag manager api to execute code after all tags in datalayer have been executed\n });\n }\n\n trackLinkClickAndGotoUrl(category, action, label, url, value = 0) {\n const callback = () => {\n location.href = url;\n };\n this.trackLinkClickAndCallback(\n category,\n action,\n label,\n callback,\n value\n );\n }\n}\n\nexport default new GoogleTagManagerService();\n"],"sourceRoot":""}