11'use client' ;
22
3- import { useCallback , useReducer , useState } from 'react' ;
4- import Script from 'next/script' ;
3+ import { useCallback , useEffect , useReducer , useRef , useState } from 'react' ;
54import styles from './page.module.css' ;
65import PageLoadPixel from '@/components/page-load-pixel/page-load-pixel' ;
76import ConsentForm from '@/components/consent-form/consent-form' ;
@@ -29,20 +28,24 @@ import {
2928 ZENDESK_YES_BUTTON_IDENTIFIER ,
3029 ZENDESK_NO_BUTTON_IDENTIFIER ,
3130 ZENDESK_SCRIPT_TAG_ID ,
32- ZENDESK_HIDDEN_IFRAME_SELECTOR ,
3331} from '@/constants/zendesk-selectors' ;
3432import { ZENDESK_IFRAME_STYLES } from '@/constants/zendesk-styles' ;
3533import { getCSSVariable } from '@/utils/get-css-variable' ;
3634import { getSlugFromUrl } from '@/utils/get-slug-from-url' ;
3735import { widgetReducer , initialWidgetState } from '@/reducers/widget-reducer' ;
3836import { setStorageWithExpiry } from '@/utils/set-storage-with-expiry' ;
3937import { deleteStorageKeysBySuffix } from '@/utils/delete-storage-keys-by-suffix' ;
38+ import { cleanupZendesk } from '@/utils/cleanup-zendesk' ;
4039
4140export default function Home ( ) {
4241 const [ widgetState , dispatch ] = useReducer ( widgetReducer , initialWidgetState ) ;
4342 const { zendeskReady, loadWidget, firstMessageSent } = widgetState ;
4443 const [ isBurning , setIsBurning ] = useState ( false ) ;
4544 const [ showConfirmDialog , setShowConfirmDialog ] = useState ( false ) ;
45+ const scriptLoadedRef = useRef ( false ) ;
46+ const initializeZendeskRef = useRef < ( ( retries ?: number ) => void ) | null > (
47+ null ,
48+ ) ;
4649
4750 const onContinue = useCallback ( ( ) => {
4851 window . firePixelEvent ?.( 'consent' ) ;
@@ -121,8 +124,14 @@ export default function Home() {
121124 // clear `ZD-widgetOpen`
122125 sessionStorage . clear ( ) ;
123126
127+ // Clean up all Zendesk DOM elements, scripts, and globals
128+ cleanupZendesk ( ) ;
129+
124130 // Reset state to clear UI elements
125131 dispatch ( { type : 'RESET_STATE' } ) ;
132+
133+ // Reset script loaded flag so script will reload on next mount
134+ scriptLoadedRef . current = false ;
126135 } ) ;
127136 } , ZENDESK_RESET_DELAY_MS ) ;
128137 } , [ dispatch ] ) ;
@@ -142,88 +151,112 @@ export default function Home() {
142151 behavior : prefersReducedMotion ? 'auto' : 'smooth' ,
143152 } ) ;
144153
145- // Clear contents of messaging-container div (Zendesk iframe, etc.)
146- const messagingContainer = document . getElementById ( EMBEDDED_TARGET_ELEMENT ) ;
147- if ( messagingContainer ) {
148- messagingContainer . innerHTML = '' ;
149- }
154+ // Stop burn animation
155+ setIsBurning ( false ) ;
156+ } , [ ] ) ;
150157
151- // Remove hidden Zendesk iframe (data-product="web_widget")
152- const hiddenIframe = document . querySelector ( ZENDESK_HIDDEN_IFRAME_SELECTOR ) ;
153- if ( hiddenIframe ) {
154- hiddenIframe . remove ( ) ;
155- }
158+ const initializeZendesk = useCallback (
159+ ( retries = 5 ) => {
160+ // Wait a bit to ensure zE is available and messaging-container exists
161+ setTimeout ( ( ) => {
162+ try {
163+ // Check if messaging-container exists
164+ const messagingContainer = document . getElementById (
165+ EMBEDDED_TARGET_ELEMENT ,
166+ ) ;
167+ if ( ! messagingContainer ) {
168+ if ( retries > 0 ) {
169+ initializeZendeskRef . current ?.( retries - 1 ) ;
170+ }
171+ return ;
172+ }
156173
157- // Remove ze-snippet script element
158- const zeSnippet = document . getElementById ( ZENDESK_SCRIPT_TAG_ID ) ;
159- if ( zeSnippet ) {
160- zeSnippet . remove ( ) ;
161- }
174+ // Check if zE exists (script might not have initialized yet)
175+ if ( typeof zE === 'undefined' ) {
176+ if ( retries > 0 ) {
177+ initializeZendeskRef . current ?.( retries - 1 ) ;
178+ }
179+ return ;
180+ }
162181
163- // Clean up Zendesk global objects
164- if ( typeof window !== 'undefined' ) {
165- // Remove zE function if it exists
166- try {
167- delete ( window as unknown as { zE ?: unknown } ) . zE ;
168- } catch {
169- // Ignore errors if zE is not configurable
170- }
182+ // Set cookies and theme customization first
183+ zE ( 'messenger:set' , 'cookies' , 'functional' ) ;
184+ zE ( 'messenger:set' , 'customization' , {
185+ common : {
186+ hideHeader : true ,
187+ } ,
188+ theme : {
189+ message : getCSSVariable ( '--sds-color-palette-blue-60' ) ,
190+ action : getCSSVariable ( '--sds-color-palette-blue-60' ) ,
191+ onAction : '#FAFAFA' ,
192+ businessMessage : '#F2F2F2' , // Chat response background
193+ onBusinessMessage : getCSSVariable ( '--sds-color-text-01' ) ,
194+ background : 'transparent' , // Chat window background
195+ onBackground : '#666666' ,
196+ error : '#FF1744' ,
197+ onError : '#FFFFFF' ,
198+ notify : '#FF007F' ,
199+ onNotify : '#FFFFFF' ,
200+ } ,
201+ } ) ;
171202
172- // Remove zEMessenger if it exists
173- try {
174- delete ( window as unknown as { zEMessenger ?: unknown } ) . zEMessenger ;
175- } catch {
176- // Ignore errors if zEMessenger is not configurable
177- }
203+ // Render the embedded messenger
204+ zE ( 'messenger' , 'render' , {
205+ mode : 'embedded' ,
206+ widget : {
207+ targetElement : `#${ EMBEDDED_TARGET_ELEMENT } ` ,
208+ } ,
209+ } ) ;
210+
211+ // Set ready after a delay to allow widget to render
212+ setTimeout ( ( ) => {
213+ dispatch ( { type : 'SET_ZENDESK_READY' } ) ;
214+ } , ZENDESK_READY_DELAY_MS ) ;
215+ } catch ( error ) {
216+ window . fireJse ?.( error ) ;
217+ }
218+ } , 50 ) ;
219+ } ,
220+ [ dispatch ] ,
221+ ) ;
222+
223+ // Store initializeZendesk in a ref to enable recursive calls
224+ useEffect ( ( ) => {
225+ initializeZendeskRef . current = initializeZendesk ;
226+ } , [ initializeZendesk ] ) ;
227+
228+ // Manually load Zendesk script when loadWidget becomes true
229+ useEffect ( ( ) => {
230+ if ( ! loadWidget || scriptLoadedRef . current ) {
231+ return ;
178232 }
179233
180- // Stop burn animation
181- setIsBurning ( false ) ;
182- } , [ ] ) ;
234+ // Check if script already exists
235+ const existingScript = document . getElementById ( ZENDESK_SCRIPT_TAG_ID ) ;
236+ if ( existingScript ) {
237+ // Script already exists, just initialize
238+ initializeZendesk ( ) ;
239+ scriptLoadedRef . current = true ;
240+ return ;
241+ }
183242
184- const handleOnError = useCallback ( ( e : Error ) => {
185- window . fireJse ?.( e ) ;
186- } , [ ] ) ;
243+ // Create and inject script tag manually
244+ const script = document . createElement ( 'script' ) ;
245+ script . id = ZENDESK_SCRIPT_TAG_ID ;
246+ script . src = ZENDESK_SCRIPT_URL ;
247+ script . async = true ;
187248
188- const handleOnLoad = useCallback ( ( ) => {
189- try {
190- // Set cookies and theme customization first
191- zE ( 'messenger:set' , 'cookies' , 'functional' ) ;
192- zE ( 'messenger:set' , 'customization' , {
193- common : {
194- hideHeader : true ,
195- } ,
196- theme : {
197- message : getCSSVariable ( '--sds-color-palette-blue-60' ) ,
198- action : getCSSVariable ( '--sds-color-palette-blue-60' ) ,
199- onAction : '#FAFAFA' ,
200- businessMessage : '#F2F2F2' , // Chat response background
201- onBusinessMessage : getCSSVariable ( '--sds-color-text-01' ) ,
202- background : 'transparent' , // Chat window background
203- onBackground : '#666666' ,
204- error : '#FF1744' ,
205- onError : '#FFFFFF' ,
206- notify : '#FF007F' ,
207- onNotify : '#FFFFFF' ,
208- } ,
209- } ) ;
249+ script . onload = ( ) => {
250+ scriptLoadedRef . current = true ;
251+ initializeZendesk ( ) ;
252+ } ;
210253
211- // Render the embedded messenger
212- zE ( 'messenger' , 'render' , {
213- mode : 'embedded' ,
214- widget : {
215- targetElement : `#${ EMBEDDED_TARGET_ELEMENT } ` ,
216- } ,
217- } ) ;
254+ script . onerror = ( ) => {
255+ window . fireJse ?.( new Error ( 'Failed to load Zendesk script' ) ) ;
256+ } ;
218257
219- // Set ready after a delay to allow widget to render
220- setTimeout ( ( ) => {
221- dispatch ( { type : 'SET_ZENDESK_READY' } ) ;
222- } , ZENDESK_READY_DELAY_MS ) ;
223- } catch ( error ) {
224- window . fireJse ?.( error ) ;
225- }
226- } , [ dispatch ] ) ;
258+ document . head . appendChild ( script ) ;
259+ } , [ loadWidget , initializeZendesk ] ) ;
227260
228261 return (
229262 < >
@@ -272,14 +305,6 @@ export default function Home() {
272305
273306 { ! loadWidget && < ConsentForm onContinue = { onContinue } /> }
274307 </ main >
275- { loadWidget && (
276- < Script
277- id = { ZENDESK_SCRIPT_TAG_ID }
278- src = { ZENDESK_SCRIPT_URL }
279- onLoad = { handleOnLoad }
280- onError = { handleOnError }
281- />
282- ) }
283308 < PageLoadPixel />
284309 </ >
285310 ) ;
0 commit comments