1// Klaviyo Integration Helper 2// Handles Klaviyo list fetching, selection, and UI management for the property panel 3 4export class KlaviyoHelper { 5 constructor(propertyPanelController) { 6 this.propertyPanel = propertyPanelController 7 } 8 9 // Check if property has Klaviyo integration and show/hide appropriate UI 10 updateKlaviyoIntegrationVisibility() { 11 if (!this.propertyPanel.popupBuilderController) return 12 13 // Check if property has Klaviyo integration 14 const hasKlaviyoIntegration = this.propertyPanel.popupBuilderController.hasKlaviyoIntegrationValue 15 16 if (hasKlaviyoIntegration) { 17 // Show list controls, hide warning 18 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 19 this.propertyPanel.klaviyoListControlsTarget.classList.remove('hidden') 20 } 21 if (this.propertyPanel.hasKlaviyoWarningTarget) { 22 this.propertyPanel.klaviyoWarningTarget.classList.add('hidden') 23 } 24 } else { 25 // Show warning, hide list controls 26 if (this.propertyPanel.hasKlaviyoWarningTarget) { 27 this.propertyPanel.klaviyoWarningTarget.classList.remove('hidden') 28 } 29 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 30 this.propertyPanel.klaviyoListControlsTarget.classList.add('hidden') 31 } 32 } 33 } 34 35 // Fetch Klaviyo lists from the API 36 async fetchKlaviyoLists() { 37 if (!this.propertyPanel.popupBuilderController) return 38 39 // Show loading state 40 this.propertyPanel.klaviyoLoadingStateTarget.classList.remove('hidden') 41 this.propertyPanel.klaviyoErrorStateTarget.classList.add('hidden') 42 this.propertyPanel.klaviyoListGroupTarget.classList.add('hidden') 43 this.propertyPanel.selectedKlaviyoListDisplayTarget.classList.add('hidden') 44 45 try { 46 // Get the current popup ID - only proceed if we have one 47 const popupId = this.propertyPanel.popupBuilderController.currentPopupId 48 if (!popupId || popupId === 'undefined' || popupId === 'null') { 49 throw new Error('No popup selected. Please save your popup first.') 50 } 51 52 const response = await fetch(`/popups/${popupId}/klaviyo_lists`, { 53 method: 'GET', 54 headers: { 55 'Content-Type': 'application/json', 56 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content') 57 } 58 }) 59 60 const data = await response.json() 61 62 if (!response.ok) { 63 throw new Error(data.error || 'Failed to fetch Klaviyo lists') 64 } 65 66 // Hide loading state 67 this.propertyPanel.klaviyoLoadingStateTarget.classList.add('hidden') 68 69 if (data.lists && data.lists.length > 0) { 70 // Populate the dropdown 71 this.populateKlaviyoListDropdown(data.lists) 72 this.propertyPanel.klaviyoListGroupTarget.classList.remove('hidden') 73 74 // Hide the fetch button section after successful fetch 75 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 76 const fetchSection = this.propertyPanel.klaviyoListControlsTarget.querySelector('.flex.items-center.justify-between') 77 if (fetchSection) { 78 fetchSection.classList.add('hidden') 79 } 80 } 81 } else { 82 // Show no lists message 83 this.propertyPanel.klaviyoErrorMessageTarget.textContent = 'No Klaviyo lists found' 84 this.propertyPanel.klaviyoErrorStateTarget.classList.remove('hidden') 85 86 // Show fetch button section on error (user can retry) 87 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 88 const fetchSection = this.propertyPanel.klaviyoListControlsTarget.querySelector('.flex.items-center.justify-between') 89 if (fetchSection) { 90 fetchSection.classList.remove('hidden') 91 } 92 } 93 } 94 95 } catch (error) { 96 console.error('Error fetching Klaviyo lists:', error) 97 98 // Hide loading state and show error 99 this.propertyPanel.klaviyoLoadingStateTarget.classList.add('hidden') 100 this.propertyPanel.klaviyoErrorMessageTarget.textContent = error.message 101 this.propertyPanel.klaviyoErrorStateTarget.classList.remove('hidden') 102 103 // Show fetch button section on error (user can retry) 104 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 105 const fetchSection = this.propertyPanel.klaviyoListControlsTarget.querySelector('.flex.items-center.justify-between') 106 if (fetchSection) { 107 fetchSection.classList.remove('hidden') 108 } 109 } 110 } 111 } 112 113 // Populate the Klaviyo list dropdown with fetched lists
114 populateKlaviyoListDropdown(lists) { 115 // Clear existing options except the first one 116 this.propertyPanel.klaviyoListSelectTarget.innerHTML = '<option value="">No list selected</option>' 117 118 // Add each list as an option 119 lists.forEach(list => { 120 const option = document.createElement('option') 121 option.value = list.id 122 option.textContent = list.name 123 option.setAttribute('data-list-name', list.name) 124 this.propertyPanel.klaviyoListSelectTarget.appendChild(option) 125 }) 126 } 127 128 // Update popup settings when a Klaviyo list is selected 129 updateKlaviyoList() { 130 if (!this.propertyPanel.popupBuilderController) return 131 132 const selectedOption = this.propertyPanel.klaviyoListSelectTarget.selectedOptions[0] 133 134 if (selectedOption && selectedOption.value) { 135 const listId = selectedOption.value 136 const listName = selectedOption.getAttribute('data-list-name') 137 138 // Update the popup settings with the selected list 139 this.propertyPanel.popupBuilderController.updatePopupSettings({ 140 klaviyoListId: listId, 141 klaviyoListName: listName 142 }) 143 144 // Show the selected list display 145 this.propertyPanel.selectedListNameTarget.textContent = listName 146 this.propertyPanel.selectedListIdTarget.textContent = listId 147 this.propertyPanel.selectedKlaviyoListDisplayTarget.classList.remove('hidden') 148 this.propertyPanel.klaviyoListGroupTarget.classList.add('hidden') 149 150 } else { 151 // Clear the selection 152 this.clearKlaviyoList() 153 } 154 } 155 156 // Clear the selected Klaviyo list 157 clearKlaviyoList() { 158 if (!this.propertyPanel.popupBuilderController) return 159 160 // Clear the popup settings 161 this.propertyPanel.popupBuilderController.updatePopupSettings({ 162 klaviyoListId: null, 163 klaviyoListName: null 164 }) 165 166 // Reset the UI 167 this.propertyPanel.klaviyoListSelectTarget.value = '' 168 this.propertyPanel.selectedKlaviyoListDisplayTarget.classList.add('hidden') 169 this.propertyPanel.klaviyoListGroupTarget.classList.add('hidden') // Hide dropdown (it's empty after clearing) 170 171 // Show the fetch button section again 172 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 173 const fetchSection = this.propertyPanel.klaviyoListControlsTarget.querySelector('.flex.items-center.justify-between') 174 if (fetchSection) { 175 fetchSection.classList.remove('hidden') 176 } 177 } 178 } 179 180 // Initialize Klaviyo list display if one is already selected 181 initializeKlaviyoListDisplay() { 182 if (!this.propertyPanel.popupBuilderController) return 183 184 const popupSettings = this.propertyPanel.popupBuilderController.popupSettings 185 if (popupSettings.klaviyoListId && popupSettings.klaviyoListName) { 186 // Show selected list display with saved data 187 this.propertyPanel.selectedListNameTarget.textContent = popupSettings.klaviyoListName 188 this.propertyPanel.selectedListIdTarget.textContent = popupSettings.klaviyoListId 189 this.propertyPanel.selectedKlaviyoListDisplayTarget.classList.remove('hidden') 190 191 // Hide the fetch lists controls since a list is already selected 192 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 193 // Only hide the fetch button section, not the entire controls container 194 const fetchSection = this.propertyPanel.klaviyoListControlsTarget.querySelector('.flex.items-center.justify-between') 195 if (fetchSection) { 196 fetchSection.classList.add('hidden') 197 } 198 } 199 if (this.propertyPanel.hasKlaviyoListGroupTarget) { 200 this.propertyPanel.klaviyoListGroupTarget.classList.add('hidden') 201 } 202 } else { 203 // No saved list, show fetch controls and hide selected display 204 this.propertyPanel.selectedKlaviyoListDisplayTarget.classList.add('hidden') 205 if (this.propertyPanel.hasKlaviyoListControlsTarget) { 206 const fetchSection = this.propertyPanel.klaviyoListControlsTarget.querySelector('.flex.items-center.justify-between') 207 if (fetchSection) { 208 fetchSection.classList.remove('hidden') 209 } 210 } 211 } 212 } 213} 214;
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.