/** * event send to parent window */ const JOLIBOX_CUSTOM_ADS_EVENT_TYPE = 'JOLIBOX_ADS_EVENT'; const JOLIBOX_CUSTOM_REWARDS_EVENT_TYPE = 'JOLIBOX_CUSTOM_REWARDS_EVENT'; const JOLIBOX_TOPUP_EVENT = 'JOLIBOX_TOPUP_EVENT'; const JOLIBOX_JOLI_COIN_USE_EVENT = 'JOLIBOX_JOLI_COIN_USE_EVENT'; const JOLIBOX_JOLI_UNLOGIN_MODAL_EVENT = 'JOLIBOX_JOLI_UNLOGIN_MODAL_EVENT'; // unlogin modal event, triggered when unlogin // unlogin modal result event success. // subscrition const JOLIBOX_GET_USER_SUB_STATUS = 'JOLIBOX_GET_USER_SUB_STATUS'; const JOLIBOX_SUB_EVENT = 'JOLIBOX_SUB_EVENT'; const CP_LOAD_FINISH = 'CP_LOAD_FINISH'; const CP_LOAD_PROGRESS = 'CP_LOAD_PROGRESS'; const CP_GAME_TTI = 'CP_GAME_TTI'; interface JoliboxCustomEvent { [JOLIBOX_CUSTOM_ADS_EVENT_TYPE]: { isAdShowing: boolean; }; [JOLIBOX_CUSTOM_REWARDS_EVENT_TYPE]: { ['JOLI_COIN']?: { quantity: number; balance: number; }; }; [JOLIBOX_TOPUP_EVENT]: { ['JOLI_COIN']?: { quantity: number; balance: number; enableAutoDeduct?: boolean; }; type: 'ADS-JOLI_COIN' | 'JOLI_COIN'; sequenceId: string; }; // [JOLIBOX_JOLI_COIN_USE_EVENT]: { ['JOLI_COIN']?: { quantity: number; balance: number; enableAutoDeduct?: boolean; }; type: 'ADS-JOLI_COIN' | 'JOLI_COIN'; sequenceId: string; }; [JOLIBOX_JOLI_UNLOGIN_MODAL_EVENT]: { sequenceId: string; type: 'ADS-JOLI_COIN' | 'JOLI_COIN'; }; [JOLIBOX_GET_USER_SUB_STATUS]: { sequenceId: string; }; [JOLIBOX_SUB_EVENT]: { sequenceId: string; }; [CP_LOAD_FINISH]: { // no data }; [CP_LOAD_PROGRESS]: { progress: number; }; [CP_GAME_TTI]: { duration?: number; }; } const notifyCustomEvent = (eventName: T, data: JoliboxCustomEvent[T]) => { window.dispatchEvent(new CustomEvent(eventName, { detail: data })); const parentWindow = window.parent; if (parentWindow && parentWindow !== window && typeof parentWindow.postMessage === 'function') { parentWindow.postMessage( { type: eventName, data: { detail: data } }, '*' ); } }; /** * received event to parent window * @param eventName * @param data */ const ON_JOLIBOX_TOPUP_JOLI_COIN_RESULT = 'ON_JOLIBOX_TOPUP_JOLI_COIN_RESULT'; const ON_JOLIBOX_JOLI_COIN_USE_RESULT = 'ON_JOLIBOX_JOLI_COIN_USE_RESULT'; const ON_JOLIBOX_JOLI_UNLOGIN_MODAL_RESULT_EVENT = 'ON_JOLIBOX_JOLI_UNLOGIN_MODAL_RESULT_EVENT'; // subscription const ON_GET_USER_SUB_STATUS = 'ON_JOLIBOX_GET_USER_SUB_STATUS'; const ON_JOLIBOX_SUB_RESULT_EVENT = 'ON_JOLIBOX_SUB_RESULT_EVENT'; interface ReceivedJoliboxCustomEvent { [ON_JOLIBOX_TOPUP_JOLI_COIN_RESULT]: { sequenceId: string; result: 'SUCCESS' | 'CANCEL' | 'ADS'; type: 'ADS-JOLI_COIN' | 'JOLI_COIN'; joliCoin: { enableAutoDeduct: boolean; balance: number; }; }; [ON_JOLIBOX_JOLI_COIN_USE_RESULT]: { sequenceId: string; result: 'USE_COIN' | 'ADS' | 'CANCEL'; }; [ON_JOLIBOX_JOLI_UNLOGIN_MODAL_RESULT_EVENT]: { sequenceId: string; result: 'SUCCESS' | 'CANCEL' | 'ADS' | 'FAILED' | 'NOT_SUPPORT'; extra?: { firstLogin?: { reward: { rewardValue: number; rewardType: 'JOLI_COIN'; }; }; }; isFirstLogin?: boolean; }; [ON_GET_USER_SUB_STATUS]: { sequenceId: string; isSubUser: boolean; userId?: string; }; [ON_JOLIBOX_SUB_RESULT_EVENT]: { sequenceId: string; result: 'SUCCESS' | 'CANCEL' | 'FAILED'; }; } type ReceivedJoliboxCustomEventResult = keyof ReceivedJoliboxCustomEvent; interface MessageData { type: T; data: ReceivedJoliboxCustomEvent[T]; } const eventCallbacks = new Map void>>(); const globalMessageHandler = (event: MessageEvent) => { if (event.source !== window.parent) { return; } try { const message = event.data as MessageData; if (message && message.type) { const callbacks = eventCallbacks.get(message.type); if (callbacks) { callbacks.forEach((callback) => { try { callback(message.data); } catch (error) { console.warn('Callback execution failed:', error); } }); } } } catch (error) { console.warn('Failed to parse message:', error); } }; let isInitialized = false; const initializeGlobalListener = () => { if (!isInitialized) { window.addEventListener('message', globalMessageHandler); isInitialized = true; } }; const onCustomEvent = ( eventName: T, callback: (data: ReceivedJoliboxCustomEvent[T]) => void ) => { initializeGlobalListener(); if (!eventCallbacks.has(eventName)) { eventCallbacks.set(eventName, new Set()); } const callbacks = eventCallbacks.get(eventName)!; callbacks.add(callback); return () => { callbacks.delete(callback); if (callbacks.size === 0) { eventCallbacks.delete(eventName); } if (eventCallbacks.size === 0) { window.removeEventListener('message', globalMessageHandler); isInitialized = false; } }; }; export { onCustomEvent, notifyCustomEvent };