@jolibox/implement 1.1.19-beta.1 → 1.1.19-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.rush/temp/package-deps_build.json +22 -15
- package/.rush/temp/shrinkwrap-deps.json +1 -1
- package/dist/common/rewards/index.d.ts +1 -10
- package/dist/common/rewards/registers/use-ads.d.ts +3 -2
- package/dist/common/rewards/registers/use-jolicoin-only.d.ts +10 -0
- package/dist/common/rewards/registers/utils/coins/index.d.ts +32 -0
- package/dist/common/rewards/registers/utils/event-listener.d.ts +15 -0
- package/dist/common/rewards/registers/utils/index.d.ts +1 -0
- package/dist/common/rewards/reward-emitter.d.ts +58 -0
- package/dist/common/rewards/reward-helper.d.ts +2 -1
- package/dist/common/utils/index.d.ts +49 -2
- package/dist/h5/api/ads.d.ts +1 -1
- package/dist/h5/http/index.d.ts +1 -1
- package/dist/h5/rewards/index.d.ts +4 -0
- package/dist/index.js +197 -3
- package/dist/index.native.js +402 -21
- package/dist/native/api/ads.d.ts +1 -1
- package/dist/native/api/login.d.ts +4 -1
- package/dist/native/rewards/index.d.ts +4 -0
- package/dist/native/ui/modal-iframe.d.ts +26 -0
- package/implement.build.log +2 -2
- package/package.json +5 -4
- package/src/common/context/index.ts +3 -3
- package/src/common/rewards/fetch-reward.ts +9 -3
- package/src/common/rewards/index.ts +1 -12
- package/src/common/rewards/registers/use-ads.ts +3 -2
- package/src/common/rewards/registers/use-jolicoin-only.ts +57 -0
- package/src/common/rewards/registers/use-jolicoin.ts +27 -77
- package/src/common/rewards/registers/utils/coins/index.ts +186 -0
- package/src/common/rewards/registers/utils/event-listener.ts +66 -0
- package/src/common/rewards/registers/utils/index.ts +8 -0
- package/src/common/rewards/reward-emitter.ts +79 -0
- package/src/common/rewards/reward-helper.ts +3 -2
- package/src/common/utils/index.ts +117 -4
- package/src/h5/api/ads.ts +65 -12
- package/src/h5/http/index.ts +2 -2
- package/src/h5/rewards/index.ts +69 -0
- package/src/native/api/ads.ts +95 -33
- package/src/native/api/login.ts +1 -1
- package/src/native/bootstrap/index.ts +5 -0
- package/src/native/rewards/index.ts +138 -0
- package/src/native/ui/modal-iframe.ts +271 -0
package/dist/native/api/ads.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import '../rewards';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface IframeModalOptions {
|
|
2
|
+
url: string;
|
|
3
|
+
height?: string;
|
|
4
|
+
showCloseButton?: boolean;
|
|
5
|
+
enableDragClose?: boolean;
|
|
6
|
+
useAnimation?: boolean;
|
|
7
|
+
onClose?: () => void;
|
|
8
|
+
onLoad?: () => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* create a half-screen iframe modal
|
|
12
|
+
*/
|
|
13
|
+
export declare function createIframeModal(options: IframeModalOptions): {
|
|
14
|
+
close: () => void;
|
|
15
|
+
};
|
|
16
|
+
declare global {
|
|
17
|
+
interface Window {
|
|
18
|
+
joliboxUI?: {
|
|
19
|
+
createIframeModal: (options: IframeModalOptions) => {
|
|
20
|
+
close: () => void;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export declare function registerIframeModalToGlobal(): () => void;
|
|
26
|
+
export {};
|
package/implement.build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Invoking: npm run clean && npm run build:esm && tsc
|
|
2
2
|
|
|
3
|
-
> @jolibox/implement@1.1.19-beta.
|
|
3
|
+
> @jolibox/implement@1.1.19-beta.6 clean
|
|
4
4
|
> rimraf ./dist
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
> @jolibox/implement@1.1.19-beta.
|
|
7
|
+
> @jolibox/implement@1.1.19-beta.6 build:esm
|
|
8
8
|
> BUILD_VERSION=$(node -p "require('./package.json').version") node esbuild.config.js --format=esm
|
|
9
9
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jolibox/implement",
|
|
3
3
|
"description": "This project is Jolibox JS-SDk implement for Native && H5",
|
|
4
|
-
"version": "1.1.19-beta.
|
|
4
|
+
"version": "1.1.19-beta.6",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@jolibox/common": "1.1.19-beta.
|
|
10
|
-
"@jolibox/types": "1.1.19-beta.
|
|
11
|
-
"@jolibox/native-bridge": "1.1.19-beta.
|
|
9
|
+
"@jolibox/common": "1.1.19-beta.6",
|
|
10
|
+
"@jolibox/types": "1.1.19-beta.6",
|
|
11
|
+
"@jolibox/native-bridge": "1.1.19-beta.6",
|
|
12
|
+
"@jolibox/ads": "1.1.19-beta.6",
|
|
12
13
|
"localforage": "1.10.0",
|
|
13
14
|
"@jolibox/ui": "1.0.0",
|
|
14
15
|
"web-vitals": "4.2.4"
|
|
@@ -3,7 +3,7 @@ import { DeviceInfo, HostInfo, HostUserInfo, SdkInfo } from './types';
|
|
|
3
3
|
import { Env } from '@jolibox/types';
|
|
4
4
|
import { parseUrlQuery, encodeJoliSourceQuery, QueryParams } from './url-parse';
|
|
5
5
|
import { getAppVersion } from '../http/xua';
|
|
6
|
-
import { getDeviceId } from '@jolibox/common';
|
|
6
|
+
import { getDeviceId, platform } from '@jolibox/common';
|
|
7
7
|
|
|
8
8
|
declare const globalThis: {
|
|
9
9
|
joliboxJSCore?: {
|
|
@@ -17,7 +17,7 @@ const defaultEnv: Env = {
|
|
|
17
17
|
model: 'UnknownModel',
|
|
18
18
|
did: getDeviceId(),
|
|
19
19
|
pixelRatio: window.devicePixelRatio || 1,
|
|
20
|
-
platform: 'h5',
|
|
20
|
+
platform: platform.isAndroid ? 'android' : platform.isiOS ? 'ios' : 'h5',
|
|
21
21
|
system: 'UnknownSystemVersion',
|
|
22
22
|
lang: 'zh'
|
|
23
23
|
},
|
|
@@ -26,7 +26,7 @@ const defaultEnv: Env = {
|
|
|
26
26
|
jssdkVersion: getAppVersion()
|
|
27
27
|
},
|
|
28
28
|
schema: window.location.href,
|
|
29
|
-
platform: 'h5'
|
|
29
|
+
platform: platform.isAndroid ? 'android' : platform.isiOS ? 'ios' : 'h5'
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
const nativeEnv = globalThis.joliboxJSCore?.env;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { UnlockOptionsEventName, unlockOptionsEmitter } from '.';
|
|
2
1
|
import { IHttpClient } from '../http';
|
|
3
2
|
import { RewardsHelper, RewardType } from './reward-helper';
|
|
4
3
|
import { IJolicoinRewardOption } from './type';
|
|
4
|
+
import { UnlockOptionsEventName, rewardsEmitter } from './reward-emitter';
|
|
5
5
|
|
|
6
6
|
const priority = () => {
|
|
7
7
|
return (a: RewardType, b: RewardType) => {
|
|
@@ -11,6 +11,12 @@ const priority = () => {
|
|
|
11
11
|
};
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
const sortRewards = (rewardsTypes: RewardType[]): RewardType[] => {
|
|
15
|
+
if (!rewardsTypes.length) return ['ADS'];
|
|
16
|
+
if (rewardsTypes.includes('JOLI_COIN') && rewardsTypes.length <= 1) return ['JOLI_COIN_ONLY'];
|
|
17
|
+
return rewardsTypes.sort(priority());
|
|
18
|
+
};
|
|
19
|
+
|
|
14
20
|
export const createRewardFetcher = (rewardsHelper: RewardsHelper) => {
|
|
15
21
|
rewardsHelper.registerRewardsFetcher(async (httpClient: IHttpClient) => {
|
|
16
22
|
const defaultRewards: RewardType[] = ['ADS'];
|
|
@@ -19,7 +25,7 @@ export const createRewardFetcher = (rewardsHelper: RewardsHelper) => {
|
|
|
19
25
|
if (res.code !== 'SUCCESS') {
|
|
20
26
|
return defaultRewards;
|
|
21
27
|
}
|
|
22
|
-
|
|
28
|
+
rewardsEmitter.emit(UnlockOptionsEventName, {
|
|
23
29
|
options: res.data?.unlockOptions || [],
|
|
24
30
|
userJoliCoin: res.extra?.joliCoin || {
|
|
25
31
|
balance: 0,
|
|
@@ -30,7 +36,7 @@ export const createRewardFetcher = (rewardsHelper: RewardsHelper) => {
|
|
|
30
36
|
const rewardsTypes =
|
|
31
37
|
res.data?.unlockOptions?.map((option) => option.type) || Array.from(defaultRewards);
|
|
32
38
|
// Sort reward types with JOLI_COIN having higher priority than ADS
|
|
33
|
-
return rewardsTypes
|
|
39
|
+
return sortRewards(rewardsTypes);
|
|
34
40
|
} catch (e) {
|
|
35
41
|
console.error('getRewardOptions error:', e);
|
|
36
42
|
return defaultRewards;
|
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
import { createRewardsHelper } from './reward-helper';
|
|
2
2
|
import { createRewardFetcher } from './fetch-reward';
|
|
3
|
-
import { EventEmitter } from '@jolibox/common';
|
|
4
|
-
import { IUnlockOption, IJoliCoin } from './type';
|
|
5
3
|
|
|
6
4
|
export const rewardsHelper = createRewardsHelper();
|
|
7
5
|
createRewardFetcher(rewardsHelper);
|
|
8
6
|
|
|
9
7
|
export * from './registers/use-ads';
|
|
10
8
|
export * from './registers/use-jolicoin';
|
|
11
|
-
|
|
12
|
-
export interface IUnlockOptionsEvent {
|
|
13
|
-
options: IUnlockOption[];
|
|
14
|
-
userJoliCoin: IJoliCoin;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const UnlockOptionsEventName = 'UNLOCK_OPTIONS_CHANGED' as const;
|
|
18
|
-
export const unlockOptionsEmitter = new EventEmitter<{
|
|
19
|
-
[UnlockOptionsEventName]: [IUnlockOptionsEvent];
|
|
20
|
-
}>();
|
|
9
|
+
export * from './registers/use-jolicoin-only';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IRewardParams } from '../../ads';
|
|
2
|
+
import { JoliboxAdsForGame } from '@jolibox/ads';
|
|
2
3
|
|
|
3
4
|
export type AdsRewardsHandler = (params: IRewardParams) => Promise<boolean>;
|
|
4
|
-
export const createAdsRewardHandler = (ads:
|
|
5
|
+
export const createAdsRewardHandler = (ads: JoliboxAdsForGame): AdsRewardsHandler => {
|
|
5
6
|
return async (params: IRewardParams) => {
|
|
6
7
|
ads.adBreak(params);
|
|
7
8
|
return true;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { IHttpClient } from '@/common/http';
|
|
2
|
+
import { rewardsEmitter, UnlockOptionsEventName, IUnlockOptionsEvent } from '../reward-emitter';
|
|
3
|
+
import { IAdBreakParams } from '@/common/ads';
|
|
4
|
+
import {
|
|
5
|
+
createCommonJolicoinRewardHandler,
|
|
6
|
+
createShowUnlockWithJolicoinModal,
|
|
7
|
+
createInitiateAndAwaitPayment
|
|
8
|
+
} from './utils/coins';
|
|
9
|
+
import { createEventPromiseHandler } from './utils/event-listener';
|
|
10
|
+
|
|
11
|
+
export type JolicoinOnlyRewardsHandler = (params: IAdBreakParams) => Promise<boolean>;
|
|
12
|
+
export const createJolicoinOnlyRewardHandler = (
|
|
13
|
+
httpClient: IHttpClient,
|
|
14
|
+
{
|
|
15
|
+
onUnlockSuccess,
|
|
16
|
+
onUnlockFailed
|
|
17
|
+
}: {
|
|
18
|
+
onUnlockSuccess?: (data: { quantity: number; balance: number }) => void;
|
|
19
|
+
onUnlockFailed?: () => void;
|
|
20
|
+
}
|
|
21
|
+
): JolicoinOnlyRewardsHandler => {
|
|
22
|
+
const unlockOptionsHandler = createEventPromiseHandler<IUnlockOptionsEvent, typeof UnlockOptionsEventName>(
|
|
23
|
+
rewardsEmitter,
|
|
24
|
+
UnlockOptionsEventName
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const handleUnlockFailed = (() => (params: IAdBreakParams) => {
|
|
28
|
+
onUnlockFailed?.();
|
|
29
|
+
params.adBreakDone?.({
|
|
30
|
+
breakType: params.type,
|
|
31
|
+
breakFormat: params.type === 'reward' ? 'reward' : 'interstitial',
|
|
32
|
+
breakStatus: 'noAdPreloaded'
|
|
33
|
+
});
|
|
34
|
+
})();
|
|
35
|
+
|
|
36
|
+
const showUnlockWithJolicoinModal = createShowUnlockWithJolicoinModal('JOLI_COIN', {
|
|
37
|
+
confirmButtonText: 'Use Jolicoin',
|
|
38
|
+
cancelButtonText: 'No thanks'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const initiateAndAwaitPayment = createInitiateAndAwaitPayment('JOLI_COIN', {
|
|
42
|
+
confirmButtonText: 'Pay and unlock',
|
|
43
|
+
cancelButtonText: 'No thanks'
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const jolicoinOnlyRewardHandler = createCommonJolicoinRewardHandler(httpClient, {
|
|
47
|
+
handlers: {
|
|
48
|
+
handleUnlockSuccess: onUnlockSuccess,
|
|
49
|
+
handleUnlockFailed,
|
|
50
|
+
unlockOptionsHandler,
|
|
51
|
+
initiateAndAwaitPayment,
|
|
52
|
+
showUnlockWithJolicoinModal
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return jolicoinOnlyRewardHandler;
|
|
57
|
+
};
|
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
import { IHttpClient } from '@/common/http';
|
|
2
|
-
import {
|
|
3
|
-
import { uuidv4 } from '@jolibox/common';
|
|
4
|
-
import { unlockOptionsEmitter, UnlockOptionsEventName, IUnlockOptionsEvent } from '..';
|
|
2
|
+
import { rewardsEmitter, UnlockOptionsEventName, IUnlockOptionsEvent } from '../reward-emitter';
|
|
5
3
|
import { IAdBreakParams } from '@/common/ads';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
code: 'SUCCESS' | 'BALANCE_NOT_ENOUGH' | 'EPISODE_LOCK_JUMP' | 'EPISODE_UNLOCK_ALREADY';
|
|
10
|
-
message: string;
|
|
11
|
-
data: {
|
|
12
|
-
transactionId: string;
|
|
13
|
-
quantity: number;
|
|
14
|
-
balance: number;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
4
|
+
import { createEventPromiseHandler } from './utils/event-listener';
|
|
5
|
+
import { createCommonJolicoinRewardHandler } from './utils/coins';
|
|
6
|
+
import { createInitiateAndAwaitPayment, createShowUnlockWithJolicoinModal } from './utils/coins';
|
|
17
7
|
|
|
18
8
|
export type JolicoinRewardsHandler = (params: IAdBreakParams) => Promise<boolean>;
|
|
19
9
|
export const createJolicoinRewardHandler = (
|
|
@@ -26,74 +16,34 @@ export const createJolicoinRewardHandler = (
|
|
|
26
16
|
onUnlockFailed?: () => void;
|
|
27
17
|
}
|
|
28
18
|
): JolicoinRewardsHandler => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
const unlockOptionsHandler = createEventPromiseHandler<IUnlockOptionsEvent, typeof UnlockOptionsEventName>(
|
|
20
|
+
rewardsEmitter,
|
|
21
|
+
UnlockOptionsEventName
|
|
22
|
+
);
|
|
32
23
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
unlockOptionsPromise = Promise.resolve(cachedUnlockOptions);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
unlockOptionsPromise = new Promise<IUnlockOptionsEvent>((resolve) => {
|
|
40
|
-
resolveUnlockOptions = resolve;
|
|
41
|
-
});
|
|
24
|
+
const handleUnlockFailed = () => {
|
|
25
|
+
onUnlockFailed?.();
|
|
42
26
|
};
|
|
43
27
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
cachedUnlockOptions = options;
|
|
48
|
-
if (resolveUnlockOptions) {
|
|
49
|
-
resolveUnlockOptions(options);
|
|
50
|
-
resolveUnlockOptions = null;
|
|
51
|
-
}
|
|
28
|
+
const showUnlockWithJolicoinModal = createShowUnlockWithJolicoinModal('ADS-JOLI_COIN', {
|
|
29
|
+
confirmButtonText: 'Use Jolicoin',
|
|
30
|
+
cancelButtonText: 'No watch ads'
|
|
52
31
|
});
|
|
53
32
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
const unlockOptions = await unlockOptionsPromise!;
|
|
60
|
-
if (!canUseJolicoin(unlockOptions?.options || [], unlockOptions?.userJoliCoin)) {
|
|
61
|
-
onUnlockFailed?.();
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
33
|
+
const initiateAndAwaitPayment = createInitiateAndAwaitPayment('ADS-JOLI_COIN', {
|
|
34
|
+
confirmButtonText: 'Pay and unlock',
|
|
35
|
+
cancelButtonText: 'No watch ads'
|
|
36
|
+
});
|
|
64
37
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
if (unlockWithJolicoin.code == 'SUCCESS') {
|
|
76
|
-
params.adBreakDone?.({
|
|
77
|
-
breakType: params.type,
|
|
78
|
-
breakName: 'name' in params ? params.name ?? '' : '',
|
|
79
|
-
breakFormat: 'reward',
|
|
80
|
-
breakStatus: 'viewed'
|
|
81
|
-
});
|
|
82
|
-
if ('adViewed' in params) {
|
|
83
|
-
params.adViewed?.();
|
|
84
|
-
}
|
|
85
|
-
onUnlockSuccess?.({
|
|
86
|
-
quantity: unlockWithJolicoin.data.quantity,
|
|
87
|
-
balance: unlockWithJolicoin.data.balance
|
|
88
|
-
});
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
onUnlockFailed?.();
|
|
92
|
-
return false;
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.error(`JolicoinRewardHandler error:`, e);
|
|
95
|
-
onUnlockFailed?.();
|
|
96
|
-
return false;
|
|
38
|
+
const jolicoinOnlyRewardHandler = createCommonJolicoinRewardHandler(httpClient, {
|
|
39
|
+
handlers: {
|
|
40
|
+
handleUnlockSuccess: onUnlockSuccess,
|
|
41
|
+
handleUnlockFailed,
|
|
42
|
+
unlockOptionsHandler,
|
|
43
|
+
initiateAndAwaitPayment,
|
|
44
|
+
showUnlockWithJolicoinModal
|
|
97
45
|
}
|
|
98
|
-
};
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return jolicoinOnlyRewardHandler;
|
|
99
49
|
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { IHttpClient } from '@/common/http';
|
|
2
|
+
import { context } from '@/common/context';
|
|
3
|
+
import { uuidv4 } from '@jolibox/common';
|
|
4
|
+
import {
|
|
5
|
+
rewardsEmitter,
|
|
6
|
+
UnlockOptionsEventName,
|
|
7
|
+
IUnlockOptionsEvent,
|
|
8
|
+
InvokePaymentEventName,
|
|
9
|
+
PaymentResultEventName,
|
|
10
|
+
IPaymentEvent,
|
|
11
|
+
IUseModalResultEvent,
|
|
12
|
+
UseModalEventName,
|
|
13
|
+
UseModalResultEventName
|
|
14
|
+
} from '@/common/rewards/reward-emitter';
|
|
15
|
+
import { IAdBreakParams } from '@/common/ads';
|
|
16
|
+
import { joliCoinIsEnough } from '../index';
|
|
17
|
+
import { createEventPromiseHandler, EventPromiseHandler } from '../event-listener';
|
|
18
|
+
import { IJoliCoin } from '@/common/rewards/type';
|
|
19
|
+
|
|
20
|
+
type IPaymentResult = 'SUCCESS' | 'FAILED' | 'CANCEL';
|
|
21
|
+
type IUseModalResult = 'CONFIRM' | 'CANCEL' | 'FAILED';
|
|
22
|
+
|
|
23
|
+
interface IJolicoinUnlockRes {
|
|
24
|
+
code: 'SUCCESS' | 'BALANCE_NOT_ENOUGH' | 'EPISODE_LOCK_JUMP' | 'EPISODE_UNLOCK_ALREADY';
|
|
25
|
+
message: string;
|
|
26
|
+
data: {
|
|
27
|
+
transactionId: string;
|
|
28
|
+
quantity: number;
|
|
29
|
+
balance: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const createInitiateAndAwaitPayment = (
|
|
34
|
+
type: 'JOLI_COIN' | 'ADS-JOLI_COIN',
|
|
35
|
+
buttons: {
|
|
36
|
+
confirmButtonText: string;
|
|
37
|
+
cancelButtonText: string;
|
|
38
|
+
}
|
|
39
|
+
) => {
|
|
40
|
+
return async (params: { userJoliCoin: IJoliCoin; joliCoinQuantity: number }) => {
|
|
41
|
+
const paymentHandler = createEventPromiseHandler<IPaymentEvent, typeof PaymentResultEventName>(
|
|
42
|
+
rewardsEmitter,
|
|
43
|
+
PaymentResultEventName
|
|
44
|
+
);
|
|
45
|
+
rewardsEmitter.emit(InvokePaymentEventName, type, {
|
|
46
|
+
userJoliCoin: params.userJoliCoin,
|
|
47
|
+
joliCoinQuantity: params.joliCoinQuantity,
|
|
48
|
+
enableAutoDeduct: params.userJoliCoin.enableAutoDeduct,
|
|
49
|
+
confirmButtonText: buttons.confirmButtonText,
|
|
50
|
+
cancelButtonText: buttons.cancelButtonText
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Wait for payment result
|
|
54
|
+
const paymentResult = await paymentHandler.getFreshData();
|
|
55
|
+
return paymentResult.paymentResult;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const createShowUnlockWithJolicoinModal = (
|
|
60
|
+
type: 'JOLI_COIN' | 'ADS-JOLI_COIN',
|
|
61
|
+
buttons: {
|
|
62
|
+
confirmButtonText: string;
|
|
63
|
+
cancelButtonText: string;
|
|
64
|
+
}
|
|
65
|
+
) => {
|
|
66
|
+
return async (params: { enableAutoDeduct: boolean; userJoliCoin: IJoliCoin; joliCoinQuantity: number }) => {
|
|
67
|
+
const modalHandler = createEventPromiseHandler<IUseModalResultEvent, typeof UseModalResultEventName>(
|
|
68
|
+
rewardsEmitter,
|
|
69
|
+
UseModalResultEventName
|
|
70
|
+
);
|
|
71
|
+
rewardsEmitter.emit(UseModalEventName, type, {
|
|
72
|
+
enableAutoDeduct: params.enableAutoDeduct,
|
|
73
|
+
userJoliCoin: params.userJoliCoin,
|
|
74
|
+
joliCoinQuantity: params.joliCoinQuantity,
|
|
75
|
+
confirmButtonText: buttons.confirmButtonText,
|
|
76
|
+
cancelButtonText: buttons.cancelButtonText
|
|
77
|
+
});
|
|
78
|
+
const modalResult = await modalHandler.getFreshData();
|
|
79
|
+
return modalResult.useModalResult;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const checkIfCancel = (result: IPaymentResult | IUseModalResult) => {
|
|
84
|
+
if (result == 'CANCEL') {
|
|
85
|
+
throw new Error('CANCEL');
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const createCommonJolicoinRewardHandler = (
|
|
90
|
+
httpClient: IHttpClient,
|
|
91
|
+
{
|
|
92
|
+
handlers: {
|
|
93
|
+
handleUnlockSuccess,
|
|
94
|
+
handleUnlockFailed,
|
|
95
|
+
unlockOptionsHandler,
|
|
96
|
+
initiateAndAwaitPayment,
|
|
97
|
+
showUnlockWithJolicoinModal
|
|
98
|
+
}
|
|
99
|
+
}: {
|
|
100
|
+
handlers: {
|
|
101
|
+
handleUnlockSuccess?: (data: { quantity: number; balance: number }) => void;
|
|
102
|
+
handleUnlockFailed?: (params: IAdBreakParams) => void;
|
|
103
|
+
unlockOptionsHandler: EventPromiseHandler<IUnlockOptionsEvent, typeof UnlockOptionsEventName>;
|
|
104
|
+
initiateAndAwaitPayment: ReturnType<typeof createInitiateAndAwaitPayment>;
|
|
105
|
+
showUnlockWithJolicoinModal: ReturnType<typeof createShowUnlockWithJolicoinModal>;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
) => {
|
|
109
|
+
return async (params: IAdBreakParams) => {
|
|
110
|
+
try {
|
|
111
|
+
let shouldSkipConfirm = false;
|
|
112
|
+
const unlockOptions = await unlockOptionsHandler.getData();
|
|
113
|
+
const joliCoinQuantity =
|
|
114
|
+
unlockOptions?.options?.find((option) => option.type === 'JOLI_COIN')?.joliCoinChoices[0]
|
|
115
|
+
.joliCoinQuantity ?? 0;
|
|
116
|
+
if (!joliCoinIsEnough(unlockOptions?.options || [], unlockOptions?.userJoliCoin)) {
|
|
117
|
+
const paymentResult = await initiateAndAwaitPayment({
|
|
118
|
+
userJoliCoin: unlockOptions?.userJoliCoin,
|
|
119
|
+
joliCoinQuantity
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
checkIfCancel(paymentResult);
|
|
123
|
+
|
|
124
|
+
if (paymentResult !== 'SUCCESS') {
|
|
125
|
+
handleUnlockFailed?.(params);
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
shouldSkipConfirm = true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const enableAutoDeduct = !!unlockOptions?.userJoliCoin?.enableAutoDeduct;
|
|
133
|
+
|
|
134
|
+
if (!shouldSkipConfirm) {
|
|
135
|
+
const shouldUnlock = await showUnlockWithJolicoinModal({
|
|
136
|
+
enableAutoDeduct,
|
|
137
|
+
userJoliCoin: unlockOptions?.userJoliCoin,
|
|
138
|
+
joliCoinQuantity
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
checkIfCancel(shouldUnlock);
|
|
142
|
+
if (shouldUnlock !== 'CONFIRM') {
|
|
143
|
+
handleUnlockFailed?.(params);
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const unlockWithJolicoin = await httpClient.post<IJolicoinUnlockRes>('/api/joli-coin/unlock', {
|
|
149
|
+
data: {
|
|
150
|
+
// TODO: support drama
|
|
151
|
+
type: 'GAME_REWARD',
|
|
152
|
+
reqId: `${uuidv4()}-${context.mpType}-${Date.now()}`,
|
|
153
|
+
gameInfo: {
|
|
154
|
+
gameId: context.mpId
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
if (unlockWithJolicoin.code == 'SUCCESS') {
|
|
159
|
+
params.adBreakDone?.({
|
|
160
|
+
breakType: params.type,
|
|
161
|
+
breakName: 'name' in params ? params.name ?? '' : '',
|
|
162
|
+
breakFormat: 'reward',
|
|
163
|
+
breakStatus: 'viewed'
|
|
164
|
+
});
|
|
165
|
+
if ('adViewed' in params) {
|
|
166
|
+
params.adViewed?.();
|
|
167
|
+
}
|
|
168
|
+
handleUnlockSuccess?.({
|
|
169
|
+
quantity: unlockWithJolicoin.data.quantity,
|
|
170
|
+
balance: unlockWithJolicoin.data.balance
|
|
171
|
+
});
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
handleUnlockFailed?.(params);
|
|
175
|
+
return false;
|
|
176
|
+
} catch (e) {
|
|
177
|
+
console.info(`JolicoinRewardHandler error:`, e);
|
|
178
|
+
if (e instanceof Error && e.message == 'CANCEL') {
|
|
179
|
+
// Cancel should terminate the reward handler, invoke unlock failed
|
|
180
|
+
throw e;
|
|
181
|
+
}
|
|
182
|
+
handleUnlockFailed?.(params);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an event promise handler for EventEmitter with tuple-based events
|
|
3
|
+
* @param emitter The event emitter
|
|
4
|
+
* @param eventName The event name to listen for
|
|
5
|
+
* @returns An object with methods to get and manage the event data
|
|
6
|
+
*/
|
|
7
|
+
export function createEventPromiseHandler<T, E extends string = string>(
|
|
8
|
+
// Type 'emitter.on' to accept any type of listener callback
|
|
9
|
+
emitter: { on: (eventName: E, listener: (...args: any[]) => void) => void },
|
|
10
|
+
eventName: E
|
|
11
|
+
) {
|
|
12
|
+
let dataPromise: Promise<T> | null = null;
|
|
13
|
+
let resolveData: ((value: T) => void) | null = null;
|
|
14
|
+
let cachedData: T | null = null;
|
|
15
|
+
|
|
16
|
+
const createDataPromise = () => {
|
|
17
|
+
if (cachedData) {
|
|
18
|
+
dataPromise = Promise.resolve(cachedData);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
dataPromise = new Promise<T>((resolve) => {
|
|
23
|
+
resolveData = resolve;
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
createDataPromise();
|
|
28
|
+
|
|
29
|
+
// The listener receives variable arguments
|
|
30
|
+
emitter.on(eventName, (...args: any[]) => {
|
|
31
|
+
// Get the first argument as the data
|
|
32
|
+
const data = args[0] as T;
|
|
33
|
+
cachedData = data;
|
|
34
|
+
if (resolveData) {
|
|
35
|
+
resolveData(data);
|
|
36
|
+
resolveData = null;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
getData: () => {
|
|
42
|
+
if (!dataPromise) {
|
|
43
|
+
createDataPromise();
|
|
44
|
+
}
|
|
45
|
+
return dataPromise as Promise<T>;
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
getCachedData: () => cachedData,
|
|
49
|
+
|
|
50
|
+
clearCache: () => {
|
|
51
|
+
cachedData = null;
|
|
52
|
+
dataPromise = null;
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
getFreshData: () => {
|
|
56
|
+
cachedData = null;
|
|
57
|
+
dataPromise = null;
|
|
58
|
+
createDataPromise();
|
|
59
|
+
return dataPromise!;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type EventPromiseHandler<T, E extends string = string> = ReturnType<
|
|
65
|
+
typeof createEventPromiseHandler<T, E>
|
|
66
|
+
>;
|
|
@@ -9,3 +9,11 @@ export const canUseJolicoin = (unlockOptions: IUnlockOption[], joliCoin?: IJoliC
|
|
|
9
9
|
)
|
|
10
10
|
);
|
|
11
11
|
};
|
|
12
|
+
|
|
13
|
+
export const joliCoinIsEnough = (unlockOptions: IUnlockOption[], joliCoin?: IJoliCoin) => {
|
|
14
|
+
return unlockOptions.some(
|
|
15
|
+
(option) =>
|
|
16
|
+
option.type === 'JOLI_COIN' &&
|
|
17
|
+
option.joliCoinChoices.some((choice) => choice.joliCoinQuantity <= (joliCoin?.balance ?? 0))
|
|
18
|
+
);
|
|
19
|
+
};
|