1/* eslint-disable import/no-cycle */ 2/* eslint-disable import/prefer-default-export */ 3 4import { initializers } from '@dropins/tools/initializer.js'; 5import { Image, provider as UI } from '@dropins/tools/components.js'; 6import { 7 initialize, 8 setEndpoint, 9 setFetchGraphQlHeaders, 10 fetchProductData, 11} from '@dropins/storefront-pdp/api.js'; 12import { initializeDropin } from './index.js'; 13import { 14 fetchPlaceholders, 15 commerceEndpointWithQueryParams, 16 getOptionsUIDsFromUrl, 17 getSkuFromUrl, 18 loadErrorPage, 19} from '../commerce.js'; 20import { getHeaders } from '../configs.js'; 21 22export const IMAGES_SIZES = { 23 width: 960, 24 height: 1191, 25}; 26 27await initializeDropin(async () => { 28 // Set Fetch Endpoint (Service) 29 setEndpoint(await commerceEndpointWithQueryParams()); 30 31 // Set Fetch Headers (Service) 32 setFetchGraphQlHeaders((prev) => ({ 33 ...prev, 34 ...getHeaders('cs'), 35 nasmprice: 'all', 36 })); 37 38 const sku = await getSkuFromUrl(); 39 const optionsUIDs = getOptionsUIDsFromUrl(); 40 41 const [product, labels] = await Promise.all([ 42 fetchProductData(sku, { optionsUIDs, skipTransform: true }).then(preloadImageMiddleware), 43 fetchPlaceholders(), 44 ]); 45 46 if (!product?.sku) { 47 // Don't load error page in authoring environment (Universal Editor) 48 // Template/default pages won't have product data and should display empty preview 49 if (!window.xwalk?.isAuthorEnv) { 50 return loadErrorPage(); 51 } 52 // In authoring environment, return early without error to allow content tree to display 53 return null; 54 } 55 56 const langDefinitions = { 57 default: { 58 ...labels, 59 }, 60 }; 61 62 const models = { 63 ProductDetails: { 64 initialData: { ...product }, 65 transformer: (rawProduct) => { 66 if (!rawProduct) return null; 67 68 // Helper function to get attribute value by name 69 const getAttributeValue = (attributeName) => { 70 const attr = rawProduct.attributes?.find((a) => a.name === attributeName); 71 return attr?.value || ''; 72 }; 73 74 // Add custom fields to the transformed product 75 return { 76 videos: rawProduct.videos || [], 77 vimeo_video: getAttributeValue('vimeo_video'), // Include vimeo video URL 78 vanity_url: getAttributeValue('vanity_url'), // Include vimeo video URL 79 eyebrowSuggestLabel: getAttributeValue('eyebrow_suggest_label'), 80 promotionEndDate: getAttributeValue('promotion_end_date'), 81 promotionStartDate: getAttributeValue('promotion_start_date'), 82 promotionLabel: getAttributeValue('promotion_label'), 83 productTitleLine2: getAttributeValue('product_title_line_2'), 84 pdpType: getAttributeValue('pdp_type'), 85 badge: getAttributeValue('badge'), 86 promotionCountdownLabel: getAttributeValue('promotion_countdown_label'), 87 marketing_product_name: getAttributeValue('marketing_product_name'), // Include marketing product name for display 88 child_eyebrow_label: getAttributeValue('child_eyebrow_label'), // Include child eyebrow label for payment plans 89 child_marketing_product_name: getAttributeValue('child_marketing_product_name'), // Include child marketing product name for payment plans 90 highlight_child_sku: getAttributeValue('highlight_child_sku'), // Include highlight_child_sku for matrix product highlighting 91 nasm_price: rawProduct.nasm_price || [], // Include nasm_price data for bundle products 92 default_instalment: getAttributeValue('default_instalment'), // Include default_instalment for bundle pricing 93 additionalCourseDetails: getAttributeValue('additional_course_details'), // New virtual bundles: "Included in this bundle" source (replaces group options) 94 mapped_products: getAttributeValue('mapped_products'), // Include mapped_products for matrix products 95 plp_price: getAttributeValue('plp_price'), // Include plp_price for subscription products 96 }; 97 }, 98 }, 99 }; 100 101 // Initialize Dropins 102 return initializers.mountImmediately(initialize, { 103 sku, 104 optionsUIDs, 105 langDefinitions, 106 models, 107 acdl: true, 108 persistURLParams: true, 109 }); 110})(); 111 112async function preloadImageMiddleware(data) { 113 const image = data?.images?.[0]?.url?.replace(/^https?:/, ''); 114 115 if (image) { 116 await UI.render(Image, { 117 src: image, 118 ...IMAGES_SIZES.mobile, 119 params: { 120 ...IMAGES_SIZES, 121 }, 122 loading: 'eager', 123 })(document.createElement('div')); 124 } 125 return data; 126}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.