1/** 2 * Zephyr Modern Theme - RileyPrint PDP Component 3 * 4 * Replaces the legacy jQuery "design return" flow for RileyPrint face-stamp 5 * products. Drives the Alpine root rendered by the `elseif ($isRileyprint)` 6 * branch in catalog/product/view.phtml. 7 * 8 * Flow: 9 * - No `?d=` param in the URL -> only the "Design Stamp" button shows. 10 * - `?d=<designId>` present -> POST {design_id, product_id} to the 11 * RileyPrint thumbnail endpoint, inject the returned preview HTML, reveal 12 * price + qty + Add-to-Cart + options, and populate the hidden 13 * `rileyprint_design` field so the design rides into the cart. 14 * 15 * Cross-subtree state: the product-options wrapper and the sticky ATC bars are 16 * rendered OUTSIDE this component's DOM root, so `hasDesign` is mirrored into 17 * Alpine.store('rileyprint') for them to gate on (mirrors the groupedWizard 18 * store pattern used elsewhere in the theme). 19 * 20 * Endpoint: HSC_PCE_IndexController::uploadRPThumbnailAction() 21 * returns JSON { thumbnail_image_html: "..." } 22 * 23 * @see app/design/frontend/zephyr/modern/template/catalog/product/view/rileyprint.phtml 24 */ 25function rileyPrint(config) { 26 config = config || {}; 27 28 return { 29 // ----- Config (injected from the template) ----- 30 productId: config.productId || 0, 31 uploadUrl: config.uploadUrl || '/designer/index/uploadRPThumbnail/', 32 33 // ----- State ----- 34 designId: '', 35 thumbnailHtml: '', 36 loading: false, 37 hasDesign: false, 38 39 init() { 40 // Mirror design state to a shared store so sibling blocks rendered 41 // outside this root (options wrapper, sticky ATC) can react. 42 this.$watch('hasDesign', (value) => { 43 if (window.Alpine && Alpine.store('rileyprint')) { 44 Alpine.store('rileyprint').hasDesign = value; 45 } 46 }); 47 48 // Design id can arrive two ways: 49 // `d` â handed back by the external RileyPrint editor on a fresh design 50 // `rpdid` â set by the cart "Edit Design" link (CartController::_getConfigureUrl) 51 // when editing an existing cart item in configure mode 52 const params = new URLSearchParams(window.location.search); 53 const designId = params.get('d') || params.get('rpdid'); 54 if (!designId) { return; } 55 56 this.designId = designId; 57 this.loading = true; 58 this.fetchThumbnail(); 59 }, 60 61 fetchThumbnail() { 62 if (!this.productId || !this.uploadUrl) { 63 this.loading = false; 64 return; 65 } 66 67 const formData = new FormData(); 68 formData.append('design_id', this.designId); 69 formData.append('product_id', this.productId); 70 71 fetch(this.uploadUrl, { 72 method: 'POST', 73 body: formData, 74 credentials: 'same-origin', 75 headers: { 'X-Requested-With': 'XMLHttpRequest' } 76 }) 77 .then((response) => { 78 if (!response.ok) { 79 throw new Error('HTTP ' + response.status); 80 } 81 return response.json(); 82 }) 83 .then((data) => { 84 // Endpoint returns { thumbnail_image_html: "..." }. 85 // Guard against a double-encoded JSON string just in case. 86 if (typeof data === 'string') { 87 try { data = JSON.parse(data); } catch (e) { /* keep as-is */ } 88 } 89 90 this.thumbnailHtml = (data && data.thumbnail_image_html) || ''; 91 this.hasDesign = true; // reveal preview + options + qty/ATC; hide Design button 92 this.loading = false; 93 94 }) 95 .catch(() => { 96 // The design id is still valid (the shopper returned from the 97 // editor), so allow checkout even if the preview image failed. 98 this.thumbnailHtml = 99 '<p class="text-brand-danger text-sm">' + 100 'We could not load your design preview, but your design is saved. ' + 101 'You can still add it to your cart.' + 102 '</p>'; 103 this.hasDesign = true; 104 this.loading = false;
105 }); 106 } 107 }; 108} 109 110// Expose the factory for Alpine's x-data="rileyPrint({...})". 111window.rileyPrint = rileyPrint; 112 113// Shared flag consumed by sibling blocks (options wrapper, sticky ATC bars) 114// that live outside the component's DOM root. 115document.addEventListener('alpine:init', () => { 116 Alpine.store('rileyprint', { 117 hasDesign: false 118 }); 119});
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.