import { Job } from '@enact/core/util'; import stringReSourceDe from '../../resources/de/strings.json'; import stringReSourceEn from '../../resources/en/strings.json'; import stringReSourceGb from '../../resources/gb/strings.json'; import stringReSourceRu from '../../resources/ru/strings.json'; import { ERROR_MESSAGES_GROUPS, SECRET_KEY } from './Config'; let _boundingRectCache = {}; const BOUNDING_RECT_IGNORE_TIME = 10; const generateUUID = () => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); }; /** * prevent multiple call * @param {*} node * @returns */ const clearBoundingRectCache = new Job(() => { _boundingRectCache = {}; }, 5000); export const getBoundingClientRect = (node) => { clearBoundingRectCache.start(); if (!node.dataset.uuid) { node.dataset.uuid = generateUUID(); } const uuid = node.dataset.uuid; if (_boundingRectCache[uuid]) { if (Date.now() - _boundingRectCache[uuid].called < BOUNDING_RECT_IGNORE_TIME) { return _boundingRectCache[uuid].boundingRect; } } const boundingRect = node.getBoundingClientRect(); _boundingRectCache[uuid] = { boundingRect: boundingRect?.toJSON(), called: Date.now(), }; return boundingRect; }; const stringReSource = { US: stringReSourceEn, GB: stringReSourceGb, DE: stringReSourceDe, RU: stringReSourceRu, }; export const $L = (str) => { let languageSetting = 'system'; let resourceKey = ''; if (typeof window === 'object' && window.store) { languageSetting = window.store.getState().localSettings.languageSetting; if (languageSetting === 'system') { resourceKey = window.store.getState().common.httpHeader?.cntry_cd; } else { resourceKey = languageSetting; } } const resource = stringReSource[resourceKey]; if (typeof str === 'object') { if (resource && resource[str.key]) { return resource[str.key].replace(/{br}/g, '{br}'); } else { return str.value; } } else if (resource && resource[str]) { return resource[str].replace(/{br}/g, '{br}'); } return str && str.replace(/{br}/g, '{br}'); }; export const createQueryString = (object) => { const parts = []; for (const key of Object.getOwnPropertyNames(object)) { if (object[key] !== null && object[key] !== undefined && object[key] !== '') { parts.push(`${key}=${encodeURIComponent(object[key])}`); } } return parts.join('&'); }; export const wait = (time) => { return new Promise((resolve) => { setTimeout(() => { resolve(); }, time); }); }; export const scaleW = (value) => { if (typeof window === 'object') { return value * (window.innerWidth / 1920); } return value; }; export const scaleH = (value) => { if (typeof window === 'object') { return value * (window.innerHeight / 1080); } return value; }; //for test let localLaunchParams = { // contentTarget: "V3_8001_Tv_PD_1_A639507_0_766", // contentTarget: "V3_8001_Tv_LS_1_USQVC_0_766", // contentTarget: "V3_8001_Tv_VS_1_6643524e649d1d4bf0ad523f_0_766", // contentTarget: "V3_8001_Tv_TD_11_820_3705018", // contentTarget: "V3_8001_Tv_HD_7_527_0", // contentTarget: "V3_8001_Tv_HP_7_527_0", // contentTarget: "V3_8001_Tv_WE_twin", // contentTarget: "V3_8001_Tv_OS_1006_Home", // contentTarget: "V3_8001_Tv_BS", // contentTarget: "V3_8001_Tv_PS", // contentTarget: "V3_8001_Tv_SC_1000_Fashion_Item", // contentTarget: "V3_8001_Tv_FB_1", // contentTarget: "V3_8001_Tv_TC_824", // contentTarget: "V3_2000_HOMEBANNER:TOP_MT_1", // contentTarget: "V3_3000_AD:TM_TM_8", // contentTarget: "V3_3000_AD:SR_SR_1", // contentTarget: "V3_2006_HOMEBANNER:6241018_HP_1_1307_2", // contentTarget: "V3_2004_HOMEBANNER:4241101_HP_9_889", // contentTarget: "V3_2001_HOMEBANNER:1240712_TM_10", }; export const getLaunchParams = () => { let params = {}; if (typeof window === 'object' && window.PalmSystem && window.PalmSystem.launchParams) { try { params = JSON.parse(window.PalmSystem.launchParams); if (params['x-webos-app-container-launch'] === true) { params = params.details; } } catch (e) { params = {}; } return params; } else { return localLaunchParams; } }; export const clearLaunchParams = () => { console.log('common.clearLaunchParams'); if (typeof window === 'object' && window.PalmSystem && window.PalmSystem.launchParams) { window.PalmSystem.launchParams = ''; } else { localLaunchParams = {}; } }; export const readLocalStorage = (key, defaultValue) => { const value = typeof window === 'object' && window.localStorage.getItem(key); if (!value && defaultValue !== undefined) { return defaultValue; } return value === 'undefined' ? null : JSON.parse(value); }; export const writeLocalStorage = (key, value) => { if (typeof window === 'object') { window.localStorage.setItem(key, JSON.stringify(value)); } }; export const convertToTimeFormat = (timeString, isIncludeDate = false) => { const date = new Date(timeString); let options = { hour: 'numeric', minute: '2-digit', hour12: true }; let pattern = ' '; if (isIncludeDate) { options = { ...options, month: '2-digit', day: '2-digit', year: 'numeric', hour: '2-digit', }; pattern = ','; } return new Intl.DateTimeFormat('en-US', options).format(date).replace(pattern, ''); }; export const getTranslate3dValueByDirection = (element, isHorizontal = true) => { try { const transformStyle = window.getComputedStyle(element).transform; if (!transformStyle || transformStyle === 'none') { throw new Error('transfrom style not found'); } const transformMatrix = transformStyle.match(/^matrix\((.+)\)$/); let index, value; if (transformMatrix) { const matrixValues = transformMatrix[1].split(', '); index = isHorizontal ? 4 : 5; value = parseFloat(Math.abs(matrixValues[index])); } return value; } catch (error) { console.error(error.message); } }; export const formatGMTString = (date) => { let string = date.toISOString().replace(/T/, ' ').replace(/\..+/, ''); return string; }; export const getSpottableDescendants = (containerId) => { let container = document.querySelector(`[data-spotlight-id="${containerId}"]`); if (container) { return container.querySelectorAll('[class*="spottable"]'); } return []; }; export const isElementInContainer = (element, container, fullyVisible = true) => { // 요소와 컨테이너의 사각형 정보 가져오기 if (typeof window === 'object') { const elementRect = getBoundingClientRect(element); const containerRect = container ? getBoundingClientRect(container) : { top: 0, left: 0, bottom: window.innerHeight, right: window.innerWidth, }; // 요소가 컨테이너의 가시 영역 안에 있는지 판단 if (fullyVisible) { return ( elementRect.top >= containerRect.top && elementRect.left >= containerRect.left && elementRect.bottom <= containerRect.bottom && elementRect.right <= containerRect.right ); } else { return ( elementRect.bottom > containerRect.top && elementRect.top < containerRect.bottom && elementRect.right > containerRect.left && elementRect.left < containerRect.right ); } } else { return false; } }; export const isChildFullyShowing = (parentNode, childNode) => { try { const parentRect = getBoundingClientRect(parentNode); const childRect = getBoundingClientRect(childNode); if ( childRect.top >= parentRect.top && childRect.left >= parentRect.left && childRect.bottom <= parentRect.bottom && childRect.right <= parentRect.right ) { return true; } } catch (e) { return true; } return false; }; export const getRectDiff = (element1, element2) => { const element1Rect = getBoundingClientRect(element1); const element2Rect = getBoundingClientRect(element2); return { right: element1Rect.right - element2Rect.right, left: element1Rect.left - element2Rect.left, top: element1Rect.top - element2Rect.top, bottom: element1Rect.bottom - element2Rect.bottom, }; }; export const getFormattingCardNo = (cardNumber) => { return `${'*'.repeat(12)}${cardNumber.slice(-4)}`.replace(/(.{4})/g, '$1-').slice(0, -1); }; export const getQRCodeUrl = ({ serverHOST, serverType, index, patnrId, prdtId, dirPurcSelYn = 'Y', prdtData, qrType, liveFlag = 'Y', entryMenu, nowMenu, }) => { if (!serverHOST) { console.error('getQRCodeUrl: Not Supported, Host is missing'); return {}; } let sdpURL = serverHOST.split('.')[0]; let countryCode = ''; if (sdpURL.indexOf('-') > 0) { countryCode = sdpURL.split('-')[1]; } else { countryCode = sdpURL; } sdpURL = sdpURL.toLowerCase(); if (serverType !== 'system') { sdpURL = serverType; } let baseUrl = ''; if (sdpURL.indexOf('qt2') >= 0) { baseUrl = 'https://qt2-m.shoptime.lgappstv.com/'; } else if (sdpURL.indexOf('qt') >= 0) { baseUrl = 'https://qt-m.shoptime.lgappstv.com/'; } else { baseUrl = 'https://m.shoptime.lgappstv.com/'; } const prdtDataStr = JSON.stringify(prdtData); const prdtDataBase64 = btoa(prdtDataStr); const encodedNowMenu = encodeURIComponent(nowMenu); const encodeEntryMenu = encodeURIComponent(entryMenu); return { detailUrl: `${baseUrl}billing?cntryCd=${countryCode}&entryMenu=${encodeEntryMenu}&nowMenu=${encodedNowMenu}&idx=${index}&qrType=${qrType}&prdtId=${prdtId}&liveFlag=${liveFlag}&patnrId=${patnrId}`, detailBuyNowUrl: `${baseUrl}billing?cntryCd=${countryCode}&qrType=billingBuyNow&entryMenu=${encodeEntryMenu}&nowMenu=${encodedNowMenu}&idx=${index}&liveFlag=${liveFlag}&patnrId=${patnrId}&prdtData=${prdtDataBase64}&dirPurcSelYn=${dirPurcSelYn}&prdtId=${prdtId}`, checkoutUrl: `${baseUrl}billing?cntryCd=${countryCode}&qrType=billingCheckOutAddress&entryMenu=${encodeEntryMenu}&nowMenu=${encodedNowMenu}&idx=${index}&liveFlag=${liveFlag}&patnrId=${patnrId}&prdtData=${prdtDataBase64}&dirPurcSelYn=${dirPurcSelYn}&prdtId=${prdtId}`, billingAddressListUrl: `${baseUrl}billing?cntryCd=${countryCode}&qrType=billingAddress&entryMenu=${encodeEntryMenu}&nowMenu=${encodedNowMenu}&idx=${index}&from=billing`, shippingAddressListUrl: `${baseUrl}billing?cntryCd=${countryCode}&qrType=billingAddress&entryMenu=${encodeEntryMenu}&nowMenu=${encodedNowMenu}&idx=${index}&from=shipping`, orderPageUrl: `${baseUrl}my_order.jsp?cntryCd=${countryCode}`, homeUrl: `${baseUrl}home.jsp?cntryCd=${countryCode}`, setupPinUrl: `${baseUrl}setup_pin.jsp?cntryCd=${countryCode}`, cardListUrl: `${baseUrl}billing?cntryCd=${countryCode}&qrType=billingPayment&entryMenu=${encodeEntryMenu}&nowMenu=${encodedNowMenu}&idx=${index}`, }; }; // ex: JANUARY 01, 2024 export const getFormattingDate = (dateString) => { const date = new Date(dateString.replace(' ', 'T')); const monthNames = [ $L('JANUARY'), $L('FEBRUARY'), $L('MARCH'), $L('APRIL'), $L('MAY'), $L('JUNE'), $L('JULY'), $L('AUGUST'), $L('SEPTEMBER'), $L('OCTOBER'), $L('NOVEMBER'), $L('DECEMBER'), ]; const month = monthNames[date.getMonth()]; const day = date.getDate().toString().padStart(2, '0'); const year = date.getFullYear(); return `${month} ${day}, ${year}`; }; export const removeSpecificTags = (html) => { // null 또는 undefined 체크 if (!html) { return html; } const tagPatterns = [ /]*>(.*?)<\/a>/gi, /]*>(.*?)<\/script>/gi, /]*>(.*?)<\/iframe>/gi, /]*\/?>/gi, /]*\/?>/gi, ]; let sanitizedHtml = html; tagPatterns.forEach((pattern) => { sanitizedHtml = sanitizedHtml.replace(pattern, ''); }); return sanitizedHtml; }; export const encryptPhoneNumber = (phoneNumber) => { if (typeof window === 'object') { return window.CryptoJS.AES.encrypt(phoneNumber, SECRET_KEY).toString(); } return phoneNumber; }; export const decryptPhoneNumber = (encryptedPhoneNumber) => { if (typeof window === 'object') { const bytes = window.CryptoJS.AES.decrypt(encryptedPhoneNumber, SECRET_KEY); return bytes.toString(window.CryptoJS.enc.Utf8); } return encryptedPhoneNumber; }; export const formatLocalDateTime = (date) => { const isDate = (obj) => Object.prototype.toString.call(obj) === '[object Date]'; if (typeof window === 'object' && isDate(date)) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } return ''; }; export const parseLocalizedNumber = (numberString, countryCode) => { // 유럽식: 1.499,00 -> 1499.00 if (countryCode === 'DE') { return parseFloat(numberString.replace(/\./g, '').replace(',', '.')); } // 미국식: 1,499.00 -> 1499.00 if (countryCode === 'US' || countryCode === 'GB') { return parseFloat(numberString.replace(/[^0-9.-]+/g, '')); } // 러시아식: 1 499,00 -> 1499.00 if (countryCode === 'RU') { return parseFloat(numberString.replace(/\s/g, '').replace(',', '.')); } return parseFloat(numberString); }; export const formatCurrencyValue = (value, currSign, currSignLoc, isDiscount = false) => { if (value === '-' || value === 0) return '-'; const numValue = parseFloat(value); if (isNaN(numValue)) return '-'; const sign = isDiscount && numValue > 0 ? '- ' : ''; const formattedValue = parseFloat(numValue.toFixed(2)).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); if (!currSign || !currSignLoc) return `${sign}${formattedValue}`; return currSignLoc === 'L' ? `${sign}${currSign} ${formattedValue}` : `${sign}${formattedValue} ${currSign}`; }; export const getTimeDifferenceByMilliseconds = ( startTimeString, endTimeString, threshold = 1000 ) => { // dateTimePattern: YYYY-MM-DD HH:MM:SS const dateTimePattern = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/; const startMatches = startTimeString.match(dateTimePattern); const endMatches = endTimeString.match(dateTimePattern); if (!startMatches || !endMatches) { return false; } const convertedStartTime = new Date(startTimeString.replace(/ /, 'T') + 'Z'); const convertedEndTime = new Date(endTimeString.replace(/ /, 'T') + 'Z'); const timeDifference = convertedEndTime - convertedStartTime; return timeDifference > threshold; }; export const getErrorMessage = (errorCode, retMsg, retDetailCode, returnBindStrings) => { const foundGroup = ERROR_MESSAGES_GROUPS.find((group) => group.codes.includes(Number(errorCode))); const errorPrefix = errorCode ? retDetailCode ? `[${errorCode}-${retDetailCode}] ` : `[${errorCode}] ` : ''; if (foundGroup) { if (errorCode === 1120 && returnBindStrings && typeof returnBindStrings === 'object') { return `${errorPrefix} ${foundGroup.message} (ID: ${returnBindStrings.join(', ')})`; } return errorPrefix + foundGroup.message; } else if (retMsg) { return errorPrefix + retMsg; } else { return errorPrefix + 'An unknown error occurred. Please try again later.'; } };