import { StandardResponse } from '@jolibox/types'; import type { IPlaceSubscriptionOrderResponse } from './type'; import { SubscriptionErrorCodeMap } from './type'; import { UserPaymentError, InternalPaymentError } from '@jolibox/common'; import { context } from '@/common/context'; import { innerFetch as fetch } from '@/native/network'; type SubscriptionStatus = 'INIT' | 'PENDING' | 'SUCCESS' | 'FAILED'; const createSubscriptionErrorFactory = () => { const [createSubscriptionError, createSubscriptionInternalError] = [ UserPaymentError, InternalPaymentError ].map((ctor) => { return (errMsg: string, errNo: number, extra?: Record) => { return new ctor(errMsg, errNo, extra); }; }); return { createSubscriptionError, createSubscriptionInternalError }; }; const { createSubscriptionError, createSubscriptionInternalError } = createSubscriptionErrorFactory(); export { createSubscriptionError, createSubscriptionInternalError }; const CALLBACK_HOST = context.testMode ? 'https://stg-game.jolibox.com' : 'https://game.jolibox.com'; export abstract class BaseSubscriptionRegister< T extends Record, E extends Record, R = void > { private _orderId: string | null = null; private _orderStatus: SubscriptionStatus = 'INIT'; startSubscription = async (params: T): Promise> => { if (this._orderId) { await this.cancelOrder(this.orderId as string); } const { code, message } = await this.placeOrder(params); if (code !== 'SUCCESS') { throw createSubscriptionError(message, SubscriptionErrorCodeMap.PlaceOrderFailed); } // invoke subscription flow return await this.subscribe(params); }; protected generateCallbackUrl = () => { // Set subscription callback parameters const originalSearch = new URLSearchParams(''); originalSearch.set('utm_source', context.deviceInfo.platform); originalSearch.set( 'joliSource', context.encodeJoliSourceQuery({ ...this.generateSubscriptionContext() }) ); return `${CALLBACK_HOST}/subscription/callback?${originalSearch.toString()}`; }; protected setOrderId(orderId: string) { this._orderId = orderId; } protected setOrderStatus(status: SubscriptionStatus) { this._orderStatus = status; } protected createSubscriptionError = createSubscriptionError; protected createSubscriptionInternalError = createSubscriptionInternalError; abstract placeOrder(params: T): Promise>>; abstract cancelOrder(orderId: string): Promise>; abstract generateSubscriptionContext(): Record; abstract subscribe(params: T): Promise>; get orderId(): string | null { return this._orderId; } get status(): SubscriptionStatus { return this._orderStatus; } }