import { IHttpClient } from '@/common/http'; import { context } from '@/common/context'; import { uuidv4 } from '@jolibox/common'; import { UnlockOptionsEventName, IUnlockOptionsEvent } from '@/common/rewards/reward-emitter'; import { IAdBreakParams } from '@/common/ads'; import { EventPromiseHandler } from '../../event-listener'; import { CURRENCY_CONFIG, CurrencyType } from '../currency-config'; import { createInitiateAndAwaitPayment, registerUsePaymentCommand, registerUseUnloginCommand, createShowUnloginModal } from '../commands'; import { registerUseJolicoinCommand, createShowUnlockWithCurrencyModal } from '../commands/use-jolicoin'; import { rewardsCommands } from '../rewards-command'; import { RewardsCommandType } from '@jolibox/types'; import { refreshGemBalanceCache, warmupGemBalanceCache } from './cached-fetch-gem-balance'; import { CURRENCY_HANDLERS } from '../commands/currency-handlers'; import { checkIfSupportSubscription } from '../../common'; interface IGemUnlockRes { code: 'SUCCESS' | 'BALANCE_NOT_ENOUGH' | 'EPISODE_LOCK_JUMP' | 'EPISODE_UNLOCK_ALREADY'; message: string; data: { transactionId: string; quantity: number; balance: number; }; } export const createCommonGemRewardHandler = ( type: 'JOLI_GEM' | 'ADS-JOLI_GEM', httpClient: IHttpClient, { handlers: { handleUnlockSuccess, handleUnlockFailed, unlockOptionsHandler, initiateAndAwaitPayment, showUnlockWithCurrencyModal, showUnloginModal, hasSubscription } }: { handlers: { handleUnlockSuccess?: (data: { quantity: number; balance: number }) => void; handleUnlockFailed?: (params: IAdBreakParams) => void; unlockOptionsHandler: EventPromiseHandler; initiateAndAwaitPayment: ReturnType; showUnlockWithCurrencyModal: ReturnType; showUnloginModal: ReturnType; hasSubscription?: () => boolean; }; } ) => { // register commands registerUseUnloginCommand(type, 'JOLI_GEM', { httpClient: httpClient, showUnloginModal: showUnloginModal }); registerUsePaymentCommand(type, 'JOLI_GEM', { httpClient: httpClient, initiateAndAwaitPayment: initiateAndAwaitPayment }); registerUseJolicoinCommand(type, 'JOLI_GEM', { showUnlockWithCurrencyModal: showUnlockWithCurrencyModal }); const commands = [`Rewards.${type}.usePayment`, `Rewards.${type}.useJolicoin`]; return async (params: IAdBreakParams) => { try { const unlockOptions = await unlockOptionsHandler.getData(); const supportSubscription = checkIfSupportSubscription(unlockOptions, hasSubscription); console.log('[GemHandler] supportSubscription', supportSubscription, unlockOptions); if (supportSubscription) { // Use currency handler for balance and quantity calculation const handler = CURRENCY_HANDLERS['JOLI_GEM']; const newBalance = await handler.fetchBalance(httpClient); const currentUser = handler.getCurrentUser(unlockOptions); const newUser = handler.createUpdatedUser(newBalance?.balance ?? 0, currentUser.enableAutoDeduct); if (!handler.isEnough(unlockOptions, newUser)) { handleUnlockFailed?.(params); return false; } } else { let result = true; for (const command of commands) { const commandResult = await rewardsCommands.executeCommand(command as RewardsCommandType); console.log('[GemHandler] command result', commandResult, command); result = result && commandResult.result !== 'FAILED'; if (commandResult.result !== 'CONTINUE') { break; } } if (!result) { handleUnlockFailed?.(params); return false; } } const config = CURRENCY_CONFIG['GEM']; const unlockWithGem = await httpClient.post(config.unlockEndpoint, { data: { type: 'GAME_REWARD', reqId: `${uuidv4()}-${context.mpType}-${Date.now()}`, gameInfo: { gameId: context.mpId } } }); console.log('-----unlockWithGem request result-----', unlockWithGem); if (unlockWithGem.code == 'SUCCESS') { try { params.adBreakDone?.({ breakType: params.type, breakName: 'name' in params ? params.name ?? '' : '', breakFormat: 'reward', breakStatus: 'viewed' }); if ('adViewed' in params) { params.adViewed?.(); } refreshGemBalanceCache(httpClient); } catch (e) { console.error('-----unlockWithGem adBreakDone error-----', e); } handleUnlockSuccess?.({ quantity: unlockWithGem.data.quantity, balance: unlockWithGem.data.balance }); return true; } handleUnlockFailed?.(params); return false; } catch (e) { console.info(`GemRewardHandler error:`, e); if (e instanceof Error && e.message == 'CANCEL') { // Cancel should terminate the reward handler, invoke unlock failed throw e; } handleUnlockFailed?.(params); return false; } finally { unlockOptionsHandler.clearCache(); } }; };