UNPKG

@mcmhomes/panorama-viewer

Version:
925 lines (862 loc) 30 kB
import {getVariationJsonData} from './utils/PanoramaVariationObtainingUtils.jsx'; import {getCorrectedGivenProps} from './utils/PanoramaPropsParsingUtils.jsx'; import {ARRAY, contains, each, filter, find, findIndex, findIndexValue, getEmptyImageSrc, INT_LAX, IS_ARRAY, IS_OBJECT, ISSET, map, mapToArray, OBJECT, STRING} from './utils/PanoramaUtils.jsx'; /** * Returns the version string of the home (unix timestamp, in millis). * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @returns {Promise<string>} */ export const getHomeVersion = async (params) => { const {homeId, homeVersion, host} = params; const {version} = await getVariationJsonData({homeId, homeVersion, host}); return STRING(version); }; /** * Returns the version date of the home. Will return new Date(0) if the version timestamp is invalid. * * The version date is the date when the home panoramas were upload. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @returns {Promise<Date>} */ export const getHomeVersionDate = async (params) => { const {homeId, homeVersion, host} = params; const versionInt = INT_LAX(await getHomeVersion({homeId, homeVersion, host})); if(versionInt <= 0) { return new Date(0); } const versionDate = new Date(versionInt); if(versionDate.toJSON() === null) { return new Date(0); } return versionDate; }; /** * Returns the render date of the home. Will return new Date(0) if the render timestamp is invalid. * * The render date is the date when the home panoramas were rendered. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @returns {Promise<Date>} */ export const getHomeRenderDate = async (params) => { const {homeId, homeVersion, host} = params; const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); const renderDateInt = INT_LAX(variationData?.renderDate); if(renderDateInt <= 0) { return new Date(0); } const renderDate = new Date(renderDateInt); if(renderDate.toJSON() === null) { return new Date(0); } return renderDate; }; /** * Returns an object with sku group IDs as keys, and arrays of SKUs as values. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @returns {Promise<Object.<string|symbol,string[]>>} */ export const getAvailableSkusGrouped = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId} = params; const {styleId, locationId} = getCorrectedGivenProps({styleId:givenStyleId, locationId:givenLocationId}); const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); let onlyVariationStyleIds = null; let onlyVariationGroupIds = null; if(locationId) { onlyVariationStyleIds = {}; onlyVariationGroupIds = {}; each(variationData?.locations, location => { if(location?.locationId === locationId) { each(location?.supportedStyleIds, styleId => { if(styleId) { onlyVariationStyleIds[styleId] = true; } }); each(location?.variationGroups, variationGroup => { if(variationGroup?.groupId) { onlyVariationGroupIds[variationGroup?.groupId] = true; } each(variationGroup?.layerDependencyGroupIds, layerDependencyGroupId => { if(layerDependencyGroupId) { onlyVariationGroupIds[layerDependencyGroupId] = true; } }); }); } }); } const result = {}; each(variationData?.styles, style => { if((!styleId || (style?.styleId === styleId)) && ((onlyVariationStyleIds === null) || (style?.styleId in onlyVariationStyleIds))) { each(style?.variationGroups, variationGroup => { if(variationGroup?.groupId && ((onlyVariationGroupIds === null) || (variationGroup?.groupId in onlyVariationGroupIds))) { const variationSkus = result[variationGroup?.groupId] ?? []; each(variationGroup?.variations, variation => { if(variation?.sku && !variationSkus.includes(variation?.sku)) { variationSkus.push(variation?.sku); } }); result[variationGroup?.groupId] = variationSkus; } }); } }); return result; }; /** * Returns an array of SKUs. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @returns {Promise<string[]>} */ export const getAvailableSkus = async (params) => { const {homeId, homeVersion, host, styleId, locationId} = params; const skusGrouped = await getAvailableSkusGrouped({homeId, homeVersion, host, styleId, locationId}); const result = []; each(skusGrouped, skus => { result.push(...skus); }); return result; }; /** * Returns an array of style IDs. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.locationId] * @returns {Promise<string[]>} */ export const getAvailableStyleIds = async (params) => { const {homeId, homeVersion, host, locationId:givenLocationId} = params; const {locationId} = getCorrectedGivenProps({locationId:givenLocationId}); const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); const location = find(variationData?.locations, location => (location?.locationId === locationId)); return filter(mapToArray(variationData?.styles, style => (!location || contains(location?.supportedStyleIds, style?.styleId)) ? STRING(style?.styleId) : null)); }; /** * Returns an array of location IDs. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @returns {Promise<string[]>} */ export const getAvailableLocationIds = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId} = params; const {styleId} = getCorrectedGivenProps({styleId:givenStyleId}); const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); return filter(mapToArray(variationData?.locations, location => (!styleId || contains(location?.supportedStyleIds, styleId)) ? STRING(location?.locationId) : null)); }; /** * Returns the default selected SKUs for the given home. * Returns an object with sku group IDs as keys, and the default SKUs as values. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @returns {Promise<Object.<string|symbol,string>>} */ export const getDefaultSkusGrouped = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId} = params; const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); const {styleId, locationId} = await getCurrentStyleAndLocationId({homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId}); const result = await getAvailableSkusGrouped({homeId, homeVersion, host, styleId, locationId}); return map(result, (skus, groupId) => { const style = find(variationData?.styles, style => (style?.styleId === styleId)); const variationGroup = find(style?.variationGroups, variationGroup => (variationGroup?.groupId === groupId)); const defaultVariationIndex = INT_LAX(variationGroup?.defaultVariationIndex); return skus[defaultVariationIndex]; }); }; /** * Returns the default selected SKUs for the given home. * Returns an array of SKUs. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @returns {Promise<string[]>} */ export const getDefaultSkus = async (params) => { const {homeId, homeVersion, host, styleId, locationId} = params; const skusGrouped = await getDefaultSkusGrouped({homeId, homeVersion, host, styleId, locationId}); const result = []; each(skusGrouped, skus => { result.push(...skus); }); return result; }; /** * Returns the default selected style ID for the given home. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.locationId] * @returns {Promise<string>} */ export const getDefaultStyleId = async (params) => { const {homeId, homeVersion, host, locationId:givenLocationId} = params; const {styleId, locationId} = await getCurrentStyleAndLocationId({homeId, homeVersion, host, locationId:givenLocationId}); return styleId; }; /** * Returns the default selected location ID for the given home. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @returns {Promise<string>} */ export const getDefaultLocationId = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId} = params; const {styleId, locationId} = await getCurrentStyleAndLocationId({homeId, homeVersion, host, styleId:givenStyleId}); return locationId; }; /** * Returns the currently selected SKUs for the given home. * Returns an object with sku group IDs as keys, and the current SKUs as values. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @param {Object.<string|symbol,string>|null} [params.skus] * @param {boolean|null} [params.warnings] * @returns {Promise<Object.<string|symbol,string>>} */ export const getCurrentSkusGrouped = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId, skus, warnings} = params; const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); const {styleId, locationId} = await getCurrentStyleAndLocationId({homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId}); const skuGroups = await getAvailableSkusGrouped({homeId, homeVersion, host, styleId, locationId}); const selectedSkuGroupIndex = mapToArray(skuGroups, (skus, groupId) => { const style = find(variationData?.styles, style => (style?.styleId === styleId)); const variationGroup = find(style?.variationGroups, variationGroup => (variationGroup?.groupId === groupId)); return INT_LAX(variationGroup?.defaultVariationIndex); }); if(IS_ARRAY(skus)) { each(skus, sku => { let skuFound = false; each(skuGroups, (skuGroup, groupId) => { let skuGroupIndex = findIndex(skuGroup, skuGroupSku => (skuGroupSku === sku)); if(ISSET(skuGroupIndex)) { selectedSkuGroupIndex[groupId] = skuGroupIndex; skuFound = true; } }); if(!skuFound && warnings) { console.warn('SKU not found:', sku); } }); } else if(IS_OBJECT(skus)) { each(skus, (sku, groupId) => { const skuGroup = skuGroups[groupId]; if(ISSET(skuGroup)) { const skuGroupIndex = findIndex(skuGroup, skuGroupSku => (skuGroupSku === sku)); if(ISSET(skuGroupIndex)) { selectedSkuGroupIndex[groupId] = skuGroupIndex; } else if(warnings) { console.warn('SKU not found in group:', sku, skuGroup); } } else if(warnings) { console.warn('SKU Group ID not found:', groupId); } }); } return map(skuGroups, (skus, groupId) => skus[selectedSkuGroupIndex[groupId]]); }; /** * Returns the currently selected SKUs for the given home. * Returns an array of SKUs. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @param {Object.<string|symbol,string>|null} [params.skus] * @param {boolean|null} [params.warnings] * @returns {Promise<string[]>} */ export const getCurrentSkus = async (params) => { const {homeId, homeVersion, host, styleId, locationId, skus, warnings} = params; const skuGroups = await getCurrentSkusGrouped({homeId, homeVersion, host, styleId, locationId, skus, warnings}); const result = []; each(skuGroups, skus => { result.push(...skus); }); return result; }; /** * Returns the currently selected style and location IDs for the given home. * * @internal * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @returns {Promise<{styleId:string, locationId:string}>} */ const getCurrentStyleAndLocationId = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId} = params; const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); const getStyleId = ({locationId = undefined}) => { const location = !locationId ? null : find(variationData?.locations, location => (location?.locationId === locationId)); let result = null; each(variationData?.styles, style => { if(!location || contains(location?.supportedStyleIds, style?.styleId)) { result = style?.styleId; return false; } }); return STRING(result); }; const getLocationId = ({styleId = undefined}) => { const style = !styleId ? null : find(variationData?.styles, style => (style?.styleId === styleId)); let result = null; each(variationData?.locations, location => { if(!style || contains(location?.supportedStyleIds, styleId)) { result = location?.locationId; return false; } }); return STRING(result); }; let {styleId, locationId} = getCorrectedGivenProps({styleId:givenStyleId, locationId:givenLocationId}); if(!styleId || !locationId) { if(!styleId && !locationId) { styleId = getStyleId({}); } if(styleId) { locationId = getLocationId({styleId}); } else { styleId = getStyleId({locationId}); } } return {styleId, locationId}; }; /** * Returns the currently selected style ID for the given home. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @returns {Promise<string>} */ export const getCurrentStyleId = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId} = params; const {styleId, locationId} = await getCurrentStyleAndLocationId({homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId}); return styleId; }; /** * Returns the currently selected location ID for the given home. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @param {string|null} [params.styleId] * @param {string|null} [params.locationId] * @returns {Promise<string>} */ export const getCurrentLocationId = async (params) => { const {homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId} = params; const {styleId, locationId} = await getCurrentStyleAndLocationId({homeId, homeVersion, host, styleId:givenStyleId, locationId:givenLocationId}); return locationId; }; /** * @exports * @typedef {Object} ThumbnailOptions * @property {number|null} [resolution] Ensures the thumbnail is at least this resolution. When 0 or below, or not provided, the highest quality image is used. * @property {string|string[]|null} [format] Thumbnail format preference. An array uses the first available format. If none match, falls back to the default format. * @property {boolean|null} [srcset] If true, the thumbnail URL will be returned as a srcset string. This is useful for responsive images. If the `resolution` parameter is also provided, it will return a DevicePixelRatio srcset (1x, 2x, etc), suitable for fixed-size images. If the `resolution` parameter is NOT provided, it will return a width-based srcset (320w, 640w, etc), in that case, the corresponding `<img>` element must include a `sizes` attribute to work correctly. */ /** * @exports * @callback AvailableThumbnailFunction * @returns {boolean} True if thumbnails are available (for this home and version), false otherwise. */ /** * @exports * @callback LocationThumbnailFunction * @param {{locationId:string} & ThumbnailOptions} params * @returns {string} URL to the thumbnail, or a transparent 1x1 image if not found. */ /** * @exports * @callback StyleThumbnailFunction * @param {{styleId:string} & ThumbnailOptions} params * @returns {string} URL to the thumbnail, or a transparent 1x1 image if not found. */ /** * @exports * @callback SkuGroupThumbnailFunction * @param {{styleId:string, groupId:string} & ThumbnailOptions} params * @returns {string} URL to the thumbnail, or a transparent 1x1 image if not found. */ /** * @exports * @callback SkuThumbnailFunction * @param {{styleId:string, groupId:string, sku:string} & ThumbnailOptions} params * @returns {string} URL to the thumbnail, or a transparent 1x1 image if not found. */ /** * @exports * @typedef {Object} ThumbnailFunctions * @property {AvailableThumbnailFunction} available * @property {LocationThumbnailFunction} location * @property {StyleThumbnailFunction} style * @property {SkuGroupThumbnailFunction} skuGroup * @property {SkuThumbnailFunction} sku */ /** * Returns an object containing functions for obtaining thumbnail URLs. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @returns {Promise<ThumbnailFunctions>} */ export const getThumbnails = async (params) => { const {homeId, homeVersion, host} = params; const {url:homeUrl, data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); const resolutions = mapToArray(variationData?.thumbnail?.resolutions, INT_LAX).sort((a, b) => a - b); const formats = mapToArray(variationData?.thumbnail?.formats, str => STRING(str).toLowerCase()); const redirects = OBJECT(variationData?.thumbnail?.redirects); const containsThumbnails = (variationData?.versionUnreal && (variationData?.versionUnreal >= '20250408') && (formats.length > 0) && (resolutions.length > 0)); const getEmptyResult = (params) => { return getEmptyImageSrc() + (params?.srcset ? ' 1x' : ''); }; const getThumbnail = (thumbnailId, params) => { if(!containsThumbnails) { return getEmptyResult(params); } thumbnailId = STRING(thumbnailId); const {resolution, format, srcset} = OBJECT(params); const formatsToUse = filter(mapToArray(ARRAY(format), str => STRING(str).toLowerCase()), format => formats.includes(format)); const formatToUse = formatsToUse[0] || formats[0] || null; if(!formatToUse) { return getEmptyResult(params); } const getUrlForResolution = (res) => { let thumbId = thumbnailId; thumbId = redirects[thumbId] ?? thumbId; thumbId = thumbId + '/' + res; thumbId = redirects[thumbId] ?? thumbId; return homeUrl + 'thumb_' + thumbId + '.' + formatToUse; }; if(srcset && !ISSET(resolution)) { const srcsetUrls = mapToArray(resolutions, res => { res = STRING(res); return getUrlForResolution(res) + ' ' + res + 'w'; }); return srcsetUrls.join(', '); } const {givenResolution, resolutionToUse} = (() => { let resolutionToUse = resolutions[resolutions.length - 1] ?? 2000; const givenResolution = INT_LAX(resolution); if(givenResolution <= 0) { return {givenResolution:resolutionToUse, resolutionToUse}; } each(resolutions, validResolution => { if(givenResolution <= validResolution) { resolutionToUse = validResolution; return false; } }); return {givenResolution, resolutionToUse}; })(); if(srcset) { const srcsetUrls = mapToArray(resolutions, res => { return getUrlForResolution(STRING(res)) + ' ' + (res / givenResolution) + 'x'; }); return srcsetUrls.join(', '); } return getUrlForResolution(resolutionToUse); }; const logMissingParameters = (functionName, paramsToCheck) => { const missingParams = filter(mapToArray(paramsToCheck, (param, paramName) => (!param ? STRING(paramName) : null))); const single = (missingParams.length === 1); console.error('Missing' + (single ? ' a' : '') + ' thumbnails.' + functionName + '() parameter' + (single ? '' : 's') + ': "' + missingParams.join('", "') + '"'); }; return { /** @type {AvailableThumbnailFunction} */ available: () => { return containsThumbnails; }, /** @type {LocationThumbnailFunction} */ location: (params) => { if(!params?.locationId) { logMissingParameters('location', {'locationId':params?.locationId}); return getEmptyResult(params); } const {locationId} = getCorrectedGivenProps(params); const locationIndex = findIndex(variationData?.locations, location => (location?.locationId === locationId)); if(!ISSET(locationIndex)) { console.warn('Location with ID not found:', params?.locationId); return getEmptyResult(params); } return getThumbnail('l_' + locationIndex, params); }, /** @type {StyleThumbnailFunction} */ style: (params) => { if(!params?.styleId) { logMissingParameters('style', {'styleId':params?.styleId}); return getEmptyResult(params); } const {styleId} = getCorrectedGivenProps(params); const styleIndex = findIndex(variationData?.styles, style => (style?.styleId === styleId)); if(!ISSET(styleIndex)) { console.warn('Style with ID not found:', params?.styleId); return getEmptyResult(params); } return getThumbnail('s_' + styleIndex, params); }, /** @type {SkuGroupThumbnailFunction} */ skuGroup: (params) => { if(!params?.styleId || !params?.groupId) { logMissingParameters('skuGroup', {'styleId':params?.styleId, 'groupId':params?.groupId}); return getEmptyResult(params); } const {styleId, groupId} = getCorrectedGivenProps(params); const {index:styleIndex, value:style} = OBJECT(findIndexValue(variationData?.styles, style => (style?.styleId === styleId))); if(!ISSET(style)) { console.warn('Style with ID not found:', params?.styleId); return getEmptyResult(params); } const groupIndex = findIndex(style?.variationGroups, variationGroup => (variationGroup?.groupId === groupId)); if(!ISSET(groupIndex)) { console.warn('SKU Group with ID not found:', params?.groupId, ' inside style:', params?.styleId); return getEmptyResult(params); } return getThumbnail('s_' + styleIndex + '_' + groupIndex, params); }, /** @type {SkuThumbnailFunction} */ sku: (params) => { if(!params?.styleId || !params?.groupId || !params?.sku) { logMissingParameters('sku', {'styleId':params?.styleId, 'groupId':params?.groupId, 'sku':params?.sku}); return getEmptyResult(params); } const {styleId, groupId, sku:skuId} = getCorrectedGivenProps(params); const {index:styleIndex, value:style} = OBJECT(findIndexValue(variationData?.styles, style => (style?.styleId === styleId))); if(!ISSET(style)) { console.warn('Style with ID not found:', params?.styleId); return getEmptyResult(params); } const {index:groupIndex, value:group} = OBJECT(findIndexValue(style?.variationGroups, variationGroup => (variationGroup?.groupId === groupId))); if(!ISSET(group)) { console.warn('SKU Group with ID not found:', params?.groupId, ' inside style:', params?.styleId); return getEmptyResult(params); } const skuIndex = findIndex(group?.variations, variation => (variation?.sku === skuId)); if(!ISSET(skuIndex)) { console.warn('SKU with ID not found:', params?.sku, ' inside group:', params?.groupId, ' inside style:', params?.styleId); return getEmptyResult(params); } return getThumbnail('s_' + styleIndex + '_' + groupIndex + '_' + skuIndex, params); }, }; }; /** * @exports * @callback AvailableNamesFunction * @returns {boolean} True if names are available (for this home and version), false otherwise. */ /** * @exports * @callback LocationNamesFunction * @param {{locationId:string}} params * @returns {string} The name of the location, or an empty string if not found. */ /** * @exports * @callback StyleNamesFunction * @param {{styleId:string}} params * @returns {string} The name of the style, or an empty string if not found. */ /** * @exports * @callback SkuGroupNamesFunction * @param {{styleId:string, groupId:string}} params * @returns {string} The name of the SKU group, or an empty string if not found. */ /** * @exports * @callback SkuNamesFunction * @param {{styleId:string, groupId:string, sku:string}} params * @returns {string} The name of the SKU, or an empty string if not found. */ /** * @exports * @typedef {Object} NamesFunctions * @property {AvailableNamesFunction} available * @property {LocationNamesFunction} location * @property {StyleNamesFunction} style * @property {SkuGroupNamesFunction} skuGroup * @property {SkuNamesFunction} sku */ /** * Returns an object containing functions for obtaining display names. * * @param {Object} params * @param {string} params.homeId * @param {string|null} [params.homeVersion] * @param {string|null} [params.host] * @returns {Promise<NamesFunctions>} */ export const getNames = async (params) => { const {homeId, homeVersion, host} = params; const {data:variationData} = await getVariationJsonData({homeId, homeVersion, host}); const containsNames = (variationData?.versionUnreal && (variationData?.versionUnreal >= '20250408')); const logMissingParameters = (functionName, paramsToCheck) => { const missingParams = filter(mapToArray(paramsToCheck, (param, paramName) => (!param ? STRING(paramName) : null))); const single = (missingParams.length === 1); console.error('Missing' + (single ? ' a' : '') + ' names.' + functionName + '() parameter' + (single ? '' : 's') + ': "' + missingParams.join('", "') + '"'); }; return { /** @type {AvailableNamesFunction} */ available: () => { return containsNames; }, /** @type {LocationNamesFunction} */ location: (params) => { if(!params?.locationId) { logMissingParameters('location', {'locationId':params?.locationId}); return ''; } const {locationId} = getCorrectedGivenProps(params); const location = find(variationData?.locations, location => (location?.locationId === locationId)); if(!location) { console.warn('Location with ID not found:', params?.locationId); return ''; } return STRING(location?.name ?? locationId); }, /** @type {StyleNamesFunction} */ style: (params) => { if(!params?.styleId) { logMissingParameters('style', {'styleId':params?.styleId}); return ''; } const {styleId} = getCorrectedGivenProps(params); const style = find(variationData?.styles, style => (style?.styleId === styleId)); if(!style) { console.warn('Style with ID not found:', params?.styleId); return ''; } return STRING(style?.name ?? styleId); }, /** @type {SkuGroupNamesFunction} */ skuGroup: (params) => { if(!params?.styleId || !params?.groupId) { logMissingParameters('skuGroup', {'styleId':params?.styleId, 'groupId':params?.groupId}); return ''; } const {styleId, groupId} = getCorrectedGivenProps(params); const style = find(variationData?.styles, style => (style?.styleId === styleId)); if(!style) { console.warn('Style with ID not found:', params?.styleId); return ''; } const group = find(style?.variationGroups, variationGroup => (variationGroup?.groupId === groupId)); if(!group) { console.warn('SKU Group with ID not found:', params?.groupId, ' inside style:', params?.styleId); return ''; } return STRING(group?.name ?? groupId); }, /** @type {SkuNamesFunction} */ sku: (params) => { if(!params?.styleId || !params?.groupId || !params?.sku) { logMissingParameters('sku', {'styleId':params?.styleId, 'groupId':params?.groupId, 'sku':params?.sku}); return ''; } const {styleId, groupId, sku:skuId} = getCorrectedGivenProps(params); const style = find(variationData?.styles, style => (style?.styleId === styleId)); if(!style) { console.warn('Style with ID not found:', params?.styleId); return ''; } const group = find(style?.variationGroups, variationGroup => (variationGroup?.groupId === groupId)); if(!group) { console.warn('SKU Group with ID not found:', params?.groupId, ' inside style:', params?.styleId); return ''; } const sku = find(group?.variations, variation => (variation?.sku === skuId)); if(!sku) { console.warn('SKU with ID not found:', params?.sku, ' inside group:', params?.groupId, ' inside style:', params?.styleId); return ''; } return STRING(sku?.name ?? skuId); }, }; };