@jolibox/implement 1.1.20 → 1.1.22
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 +12 -10
- package/dist/common/rewards/fetch-reward.d.ts +1 -0
- package/dist/common/rewards/index.d.ts +2 -0
- package/dist/common/rewards/reward-emitter.d.ts +24 -0
- package/dist/common/rewards/reward-helper.d.ts +3 -0
- package/dist/index.js +8 -8
- package/dist/index.native.js +41 -35
- package/dist/native/api/storage.d.ts +5 -0
- package/dist/native/rewards/check-frequency.d.ts +21 -0
- package/dist/native/rewards/utils.d.ts +1 -0
- package/implement.build.log +2 -2
- package/package.json +5 -5
- package/src/common/rewards/fetch-reward.ts +27 -1
- package/src/common/rewards/index.ts +2 -1
- package/src/common/rewards/reward-emitter.ts +28 -0
- package/src/common/rewards/reward-helper.ts +23 -0
- package/src/native/api/ads.ts +4 -0
- package/src/native/api/navigate.ts +21 -0
- package/src/native/api/storage.ts +45 -0
- package/src/native/bootstrap/init-env.ts +17 -0
- package/src/native/rewards/check-frequency.ts +70 -0
- package/src/native/rewards/index.ts +36 -2
- package/src/native/rewards/utils.ts +7 -0
|
@@ -23,3 +23,8 @@ export declare const getStorageInfoSync: () => StandardResponse<{
|
|
|
23
23
|
keys: string[];
|
|
24
24
|
};
|
|
25
25
|
}>;
|
|
26
|
+
export declare const getGlobalStorage: (...inputs: unknown[]) => Promise<StandardResponse<any>>;
|
|
27
|
+
export declare const setGlobalStorage: (...inputs: unknown[]) => Promise<StandardResponse<{
|
|
28
|
+
code: string;
|
|
29
|
+
message: string;
|
|
30
|
+
}>>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check can show useModal
|
|
3
|
+
* @param config
|
|
4
|
+
* @returns
|
|
5
|
+
*/
|
|
6
|
+
export declare const checkUseModalFrequency: (config: {
|
|
7
|
+
dailyMaxPopUps: number;
|
|
8
|
+
minInterval: number;
|
|
9
|
+
}) => Promise<boolean>;
|
|
10
|
+
export declare const updateUseModalFrequency: () => Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* check can show paymentModal
|
|
13
|
+
*/
|
|
14
|
+
export declare const checkPaymentFrequency: (config: {
|
|
15
|
+
dailyMaxPopUps: number;
|
|
16
|
+
minInterval: number;
|
|
17
|
+
}) => Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* update paymentFrequency
|
|
20
|
+
*/
|
|
21
|
+
export declare const updatePaymentFrequency: () => Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const filterTodayTimestamps: (timestamps: number[]) => number[];
|
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.
|
|
3
|
+
> @jolibox/implement@1.1.22 clean
|
|
4
4
|
> rimraf ./dist
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
> @jolibox/implement@1.1.
|
|
7
|
+
> @jolibox/implement@1.1.22 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,15 +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.
|
|
4
|
+
"version": "1.1.22",
|
|
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.
|
|
10
|
-
"@jolibox/types": "1.1.
|
|
11
|
-
"@jolibox/native-bridge": "1.1.
|
|
12
|
-
"@jolibox/ads": "1.1.
|
|
9
|
+
"@jolibox/common": "1.1.22",
|
|
10
|
+
"@jolibox/types": "1.1.22",
|
|
11
|
+
"@jolibox/native-bridge": "1.1.22",
|
|
12
|
+
"@jolibox/ads": "1.1.22",
|
|
13
13
|
"localforage": "1.10.0",
|
|
14
14
|
"@jolibox/ui": "1.0.0",
|
|
15
15
|
"web-vitals": "4.2.4"
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { IHttpClient } from '../http';
|
|
2
2
|
import { RewardsHelper, RewardType } from './reward-helper';
|
|
3
3
|
import { IJolicoinRewardOption } from './type';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
IUseModalFrequencyConfig,
|
|
6
|
+
UnlockOptionsEventName,
|
|
7
|
+
UseModalFrequencyEventName,
|
|
8
|
+
rewardsEmitter,
|
|
9
|
+
DefaltJoliCoinUseAndCharge
|
|
10
|
+
} from './reward-emitter';
|
|
11
|
+
import { StandardResponse } from '@jolibox/types';
|
|
5
12
|
|
|
6
13
|
const priority = () => {
|
|
7
14
|
return (a: RewardType, b: RewardType) => {
|
|
@@ -43,3 +50,22 @@ export const createRewardFetcher = (rewardsHelper: RewardsHelper) => {
|
|
|
43
50
|
}
|
|
44
51
|
});
|
|
45
52
|
};
|
|
53
|
+
|
|
54
|
+
export const createRewardFrequencyConfigFetcher = (rewardsHelper: RewardsHelper) => {
|
|
55
|
+
rewardsHelper.registerRewardFrequencyConfigFetcher(async (httpClient: IHttpClient) => {
|
|
56
|
+
const res = await httpClient.get<StandardResponse<IUseModalFrequencyConfig>>(
|
|
57
|
+
'/api/fe-configs/web-common/global-config',
|
|
58
|
+
{}
|
|
59
|
+
);
|
|
60
|
+
if (res.code !== 'SUCCESS') {
|
|
61
|
+
return { joliCoinUseAndCharge: DefaltJoliCoinUseAndCharge };
|
|
62
|
+
}
|
|
63
|
+
rewardsEmitter.emit(UseModalFrequencyEventName, {
|
|
64
|
+
joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
joliCoinUseAndCharge: res.data?.joliCoinUseAndCharge || DefaltJoliCoinUseAndCharge
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createRewardsHelper } from './reward-helper';
|
|
2
|
-
import { createRewardFetcher } from './fetch-reward';
|
|
2
|
+
import { createRewardFetcher, createRewardFrequencyConfigFetcher } from './fetch-reward';
|
|
3
3
|
|
|
4
4
|
export const rewardsHelper = createRewardsHelper();
|
|
5
5
|
createRewardFetcher(rewardsHelper);
|
|
6
|
+
createRewardFrequencyConfigFetcher(rewardsHelper);
|
|
6
7
|
|
|
7
8
|
export * from './registers/use-ads';
|
|
8
9
|
export * from './registers/use-jolicoin';
|
|
@@ -14,6 +14,7 @@ export const InvokePaymentEventName = 'INVOKE_PAYMENT' as const;
|
|
|
14
14
|
export const PaymentResultEventName = 'ON_PAYMENT_RESULT' as const;
|
|
15
15
|
export const UseModalEventName = 'ON_USE_MODAL_EVENT' as const;
|
|
16
16
|
export const UseModalResultEventName = 'ON_USE_MODAL_RESULT' as const;
|
|
17
|
+
export const UseModalFrequencyEventName = 'ON_USE_MODAL_FREQUENCY' as const;
|
|
17
18
|
|
|
18
19
|
type IPaymentResult = 'SUCCESS' | 'FAILED' | 'CANCEL';
|
|
19
20
|
export interface IPaymentEvent {
|
|
@@ -49,12 +50,26 @@ export interface IUseModalResultEvent {
|
|
|
49
50
|
useModalResult: 'CONFIRM' | 'CANCEL' | 'FAILED';
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
export interface IUseModalFrequencyConfig {
|
|
54
|
+
joliCoinUseAndCharge: {
|
|
55
|
+
useJolicoin: {
|
|
56
|
+
dailyMaxPopUps: number;
|
|
57
|
+
minInterval: number;
|
|
58
|
+
};
|
|
59
|
+
charge: {
|
|
60
|
+
dailyMaxPopUps: number;
|
|
61
|
+
minInterval: number;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
52
66
|
export interface RewardsEventMap extends Record<string, unknown[]> {
|
|
53
67
|
[UnlockOptionsEventName]: [IUnlockOptionsEvent];
|
|
54
68
|
[InvokePaymentEventName]: ['JOLI_COIN' | 'ADS-JOLI_COIN', IInvokePaymentEvent];
|
|
55
69
|
[PaymentResultEventName]: [IPaymentEvent];
|
|
56
70
|
[UseModalResultEventName]: [IUseModalResultEvent];
|
|
57
71
|
[UseModalEventName]: ['JOLI_COIN' | 'ADS-JOLI_COIN', IUseModalEvent];
|
|
72
|
+
[UseModalFrequencyEventName]: [IUseModalFrequencyConfig];
|
|
58
73
|
}
|
|
59
74
|
|
|
60
75
|
export const originalRewardsEmitter = new EventEmitter<RewardsEventMap>();
|
|
@@ -77,3 +92,16 @@ export const createRewardsEmitterWrapper = (): RewardsEmitter => {
|
|
|
77
92
|
};
|
|
78
93
|
|
|
79
94
|
export const rewardsEmitter = createRewardsEmitterWrapper();
|
|
95
|
+
|
|
96
|
+
export const DefaltJoliCoinUseAndCharge = {
|
|
97
|
+
// 充值弹窗:
|
|
98
|
+
charge: {
|
|
99
|
+
dailyMaxPopUps: 2, // 一天内最多2次弹窗
|
|
100
|
+
minInterval: 8 * 60 * 60 * 1000 // 同一用户若在8小时内刚点过弹窗,则不再弹出
|
|
101
|
+
},
|
|
102
|
+
// 使用弹窗:
|
|
103
|
+
useJolicoin: {
|
|
104
|
+
dailyMaxPopUps: 2,
|
|
105
|
+
minInterval: 8 * 60 * 60 * 1000
|
|
106
|
+
}
|
|
107
|
+
};
|
|
@@ -2,6 +2,7 @@ export type RewardType = 'ADS' | 'JOLI_COIN' | 'JOLI_COIN_ONLY';
|
|
|
2
2
|
|
|
3
3
|
import { context } from '../context';
|
|
4
4
|
import type { AdsRewardsHandler } from './registers/use-ads';
|
|
5
|
+
import { IUseModalFrequencyConfig, DefaltJoliCoinUseAndCharge } from './reward-emitter';
|
|
5
6
|
|
|
6
7
|
export interface RewardHandlerMap {
|
|
7
8
|
ADS: AdsRewardsHandler;
|
|
@@ -14,7 +15,9 @@ export type RewardHandler<T extends RewardType> = RewardHandlerMap[T];
|
|
|
14
15
|
const isTestMode = context.testMode;
|
|
15
16
|
export function createRewardsHelper() {
|
|
16
17
|
const rewardsHandlers = new Map<RewardType, RewardHandler<any>>();
|
|
18
|
+
|
|
17
19
|
let rewardFetcher: ((...args: any[]) => Promise<RewardType[]>) | undefined;
|
|
20
|
+
let rewardFrequencyConfigFetcher: ((...args: any[]) => Promise<IUseModalFrequencyConfig>) | undefined;
|
|
18
21
|
|
|
19
22
|
return {
|
|
20
23
|
registerRewardHandler<T extends RewardType>(type: T, handler: RewardHandler<T>) {
|
|
@@ -45,11 +48,31 @@ export function createRewardsHelper() {
|
|
|
45
48
|
}
|
|
46
49
|
};
|
|
47
50
|
},
|
|
51
|
+
async registerRewardFrequencyConfigFetcher(
|
|
52
|
+
fetcher: (...args: any[]) => Promise<IUseModalFrequencyConfig>
|
|
53
|
+
) {
|
|
54
|
+
rewardFrequencyConfigFetcher = async (...args: unknown[]) => {
|
|
55
|
+
try {
|
|
56
|
+
const config = await fetcher(...args);
|
|
57
|
+
return config;
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error(`getRewardOptions error:`, e);
|
|
60
|
+
return { joliCoinUseAndCharge: DefaltJoliCoinUseAndCharge };
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
|
|
48
65
|
async getRewardsTypes(...args: unknown[]): Promise<RewardType[]> {
|
|
49
66
|
if (!rewardFetcher) {
|
|
50
67
|
return ['ADS'];
|
|
51
68
|
}
|
|
52
69
|
return await rewardFetcher(...args);
|
|
70
|
+
},
|
|
71
|
+
async getRewardFrequencyConfig(...args: unknown[]): Promise<IUseModalFrequencyConfig> {
|
|
72
|
+
if (!rewardFrequencyConfigFetcher) {
|
|
73
|
+
return { joliCoinUseAndCharge: DefaltJoliCoinUseAndCharge };
|
|
74
|
+
}
|
|
75
|
+
return await rewardFrequencyConfigFetcher(...args);
|
|
53
76
|
}
|
|
54
77
|
};
|
|
55
78
|
}
|
package/src/native/api/ads.ts
CHANGED
|
@@ -76,6 +76,10 @@ const adsContext: IAdsContext<'GAME'> = {
|
|
|
76
76
|
|
|
77
77
|
const ads = new JoliboxAdsForGame(adsContext);
|
|
78
78
|
|
|
79
|
+
rewardsHelper.getRewardFrequencyConfig(httpClient).then((config) => {
|
|
80
|
+
console.log('getRewardFrequencyConfig', config);
|
|
81
|
+
});
|
|
82
|
+
|
|
79
83
|
rewardsHelper.registerRewardHandler('ADS', createAdsRewardHandler(ads));
|
|
80
84
|
rewardsHelper.registerRewardHandler(
|
|
81
85
|
'JOLI_COIN',
|
|
@@ -2,6 +2,7 @@ import { createCommands, hostEmitter, UserCustomError } from '@jolibox/common';
|
|
|
2
2
|
import { invokeNative } from '@jolibox/native-bridge';
|
|
3
3
|
import { createSyncAPI, t, registerCanIUse } from './base';
|
|
4
4
|
import { context } from '@/common/context';
|
|
5
|
+
import { reportError } from '@/common/report/errors/report';
|
|
5
6
|
|
|
6
7
|
const commands = createCommands();
|
|
7
8
|
|
|
@@ -53,10 +54,26 @@ const interceptSystemExitSync = createSyncAPI('interceptSystemExitSync', {
|
|
|
53
54
|
}
|
|
54
55
|
});
|
|
55
56
|
|
|
57
|
+
const navigateToNativePage = createSyncAPI('navigateToNativePage', {
|
|
58
|
+
paramsSchema: t.tuple(t.enum('openHistory'), t.object()),
|
|
59
|
+
implement: (path, params) => {
|
|
60
|
+
const { errNo, errMsg } = invokeNative('callHostMethodAsync', {
|
|
61
|
+
method: path,
|
|
62
|
+
params: {
|
|
63
|
+
...params
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
if (errNo !== 0) {
|
|
67
|
+
throw new UserCustomError(errMsg, errNo);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
56
72
|
commands.registerCommand('RouterSDK.openSchema', openSchemaSync);
|
|
57
73
|
commands.registerCommand('RouterSDK.openPage', openPageSync);
|
|
58
74
|
commands.registerCommand('RouterSDK.closePage', closePageSync);
|
|
59
75
|
commands.registerCommand('RouterSDK.interceptSystemExit', interceptSystemExitSync);
|
|
76
|
+
commands.registerCommand('RouterSDK.navigateToNativePage', navigateToNativePage);
|
|
60
77
|
|
|
61
78
|
registerCanIUse('router.openSchema', {
|
|
62
79
|
version: '1.1.10'
|
|
@@ -73,3 +90,7 @@ registerCanIUse('router.closePage', {
|
|
|
73
90
|
registerCanIUse('router.interceptSystemExit', {
|
|
74
91
|
version: '1.1.18'
|
|
75
92
|
});
|
|
93
|
+
|
|
94
|
+
registerCanIUse('router.navigateToNativePage', {
|
|
95
|
+
version: '1.1.19'
|
|
96
|
+
});
|
|
@@ -285,3 +285,48 @@ function stringify(data: unknown, type: DataType) {
|
|
|
285
285
|
return '';
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
+
|
|
289
|
+
export const getGlobalStorage = createAPI('getGlobalStorage', {
|
|
290
|
+
paramsSchema: t.tuple(t.string()),
|
|
291
|
+
async implement(key) {
|
|
292
|
+
try {
|
|
293
|
+
const { data, dataType } = await applyNative('getGlobalStorageAsync', { key });
|
|
294
|
+
const parsedData = parse(data, dataType);
|
|
295
|
+
return {
|
|
296
|
+
code: 'SUCCESS',
|
|
297
|
+
message: 'success',
|
|
298
|
+
data: parsedData
|
|
299
|
+
};
|
|
300
|
+
} catch (error) {
|
|
301
|
+
return {
|
|
302
|
+
code: 'INTERNAL_ERROR',
|
|
303
|
+
message: '[Jolibox SDK] get global storage failed',
|
|
304
|
+
data: null
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
export const setGlobalStorage = createAPI('setGlobalStorage', {
|
|
311
|
+
paramsSchema: t.tuple(t.string(), t.or(t.string(), t.boolean(), t.number())),
|
|
312
|
+
async implement(key, value) {
|
|
313
|
+
try {
|
|
314
|
+
const dataType = getType(value);
|
|
315
|
+
const data = stringify(value, dataType);
|
|
316
|
+
await applyNative('setGlobalStorageAsync', {
|
|
317
|
+
key,
|
|
318
|
+
data,
|
|
319
|
+
dataType
|
|
320
|
+
});
|
|
321
|
+
return {
|
|
322
|
+
code: 'SUCCESS',
|
|
323
|
+
message: 'success'
|
|
324
|
+
};
|
|
325
|
+
} catch (error) {
|
|
326
|
+
return {
|
|
327
|
+
code: 'INTERNAL_ERROR',
|
|
328
|
+
message: '[Jolibox SDK] set global storage failed'
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
});
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
export function initializeNativeEnv() {
|
|
2
2
|
let styleElement: HTMLStyleElement | null = null;
|
|
3
|
+
let viewportMeta: HTMLMetaElement | null = null;
|
|
3
4
|
const originalFetch = window.fetch;
|
|
4
5
|
const createStyles = () => {
|
|
6
|
+
// 创建并插入viewport meta标签
|
|
7
|
+
viewportMeta = document.createElement('meta');
|
|
8
|
+
viewportMeta.setAttribute('name', 'viewport');
|
|
9
|
+
viewportMeta.setAttribute(
|
|
10
|
+
'content',
|
|
11
|
+
'viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no'
|
|
12
|
+
);
|
|
13
|
+
viewportMeta.setAttribute('data-jolibox-sdk', 'viewport-meta');
|
|
14
|
+
|
|
5
15
|
styleElement = document.createElement('style');
|
|
6
16
|
styleElement.setAttribute('data-jolibox-sdk', 'default-styles');
|
|
7
17
|
|
|
@@ -28,6 +38,8 @@ export function initializeNativeEnv() {
|
|
|
28
38
|
styleElement.textContent = styles;
|
|
29
39
|
|
|
30
40
|
const head = document.head || document.getElementsByTagName('head')[0];
|
|
41
|
+
// 插入viewport meta标签
|
|
42
|
+
head.insertBefore(viewportMeta, head.firstChild);
|
|
31
43
|
head.insertBefore(styleElement, head.firstChild);
|
|
32
44
|
document.documentElement.setAttribute('data-jolibox-root', '');
|
|
33
45
|
};
|
|
@@ -72,6 +84,11 @@ export function initializeNativeEnv() {
|
|
|
72
84
|
styleElement.parentNode.removeChild(styleElement);
|
|
73
85
|
styleElement = null;
|
|
74
86
|
}
|
|
87
|
+
// 清理viewport meta标签
|
|
88
|
+
if (viewportMeta?.parentNode) {
|
|
89
|
+
viewportMeta.parentNode.removeChild(viewportMeta);
|
|
90
|
+
viewportMeta = null;
|
|
91
|
+
}
|
|
75
92
|
document.documentElement.removeAttribute('data-jolibox-root');
|
|
76
93
|
|
|
77
94
|
window.fetch = originalFetch;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { StandardResponse } from '@jolibox/types';
|
|
2
|
+
import { getGlobalStorage, setGlobalStorage } from '../api/storage';
|
|
3
|
+
import { filterTodayTimestamps } from './utils';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* check can show useModal
|
|
7
|
+
* @param config
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export const checkUseModalFrequency = async (config: { dailyMaxPopUps: number; minInterval: number }) => {
|
|
11
|
+
const { dailyMaxPopUps, minInterval } = config;
|
|
12
|
+
const res = (await getGlobalStorage('joli_coin_use_modal_frequency')) as StandardResponse<number[]>;
|
|
13
|
+
if (!res.data) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
const fequeycies = res.data;
|
|
17
|
+
const todayFequencies = filterTodayTimestamps(fequeycies);
|
|
18
|
+
if (todayFequencies.length >= dailyMaxPopUps) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
if (now - todayFequencies[todayFequencies.length - 1] < minInterval) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const updateUseModalFrequency = async () => {
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
const res = (await getGlobalStorage('joli_coin_use_modal_frequency')) as StandardResponse<number[]>;
|
|
31
|
+
|
|
32
|
+
const fequeycies = res.data ?? [];
|
|
33
|
+
fequeycies.push(now);
|
|
34
|
+
fequeycies.sort((a, b) => b - a).splice(8);
|
|
35
|
+
await setGlobalStorage('joli_coin_use_modal_frequency', fequeycies);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* check can show paymentModal
|
|
40
|
+
*/
|
|
41
|
+
export const checkPaymentFrequency = async (config: { dailyMaxPopUps: number; minInterval: number }) => {
|
|
42
|
+
const { dailyMaxPopUps, minInterval } = config;
|
|
43
|
+
const res = (await getGlobalStorage('joli_coin_payment_frequency')) as StandardResponse<number[]>;
|
|
44
|
+
|
|
45
|
+
if (!res.data) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
const fequeycies = res.data;
|
|
49
|
+
const todayFequencies = filterTodayTimestamps(fequeycies);
|
|
50
|
+
if (todayFequencies.length >= dailyMaxPopUps) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
if (now - todayFequencies[todayFequencies.length - 1] < minInterval) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* update paymentFrequency
|
|
62
|
+
*/
|
|
63
|
+
export const updatePaymentFrequency = async () => {
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
const res = (await getGlobalStorage('joli_coin_payment_frequency')) as StandardResponse<number[]>;
|
|
66
|
+
const frequencies = res.data ?? [];
|
|
67
|
+
frequencies.push(now);
|
|
68
|
+
frequencies.sort((a, b) => b - a).splice(8);
|
|
69
|
+
await setGlobalStorage('joli_coin_payment_frequency', frequencies);
|
|
70
|
+
};
|
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
UseModalResultEventName,
|
|
11
11
|
InvokePaymentEventName,
|
|
12
12
|
IInvokePaymentEvent,
|
|
13
|
-
IPaymentChoice
|
|
13
|
+
IPaymentChoice,
|
|
14
|
+
UseModalFrequencyEventName,
|
|
15
|
+
IUseModalFrequencyConfig
|
|
14
16
|
} from '@/common/rewards/reward-emitter';
|
|
15
17
|
import { createConfirmJolicoinModal, createPaymentJolicoinModal } from '@jolibox/ui';
|
|
16
18
|
import { innerFetch as fetch } from '../network';
|
|
@@ -18,13 +20,34 @@ import { StandardResponse } from '@jolibox/types';
|
|
|
18
20
|
import { context } from '@/common/context';
|
|
19
21
|
import { login } from '../api/login';
|
|
20
22
|
|
|
23
|
+
import { createEventPromiseHandler } from '@/common/rewards/registers/utils/event-listener';
|
|
24
|
+
import {
|
|
25
|
+
checkUseModalFrequency,
|
|
26
|
+
updateUseModalFrequency,
|
|
27
|
+
checkPaymentFrequency,
|
|
28
|
+
updatePaymentFrequency
|
|
29
|
+
} from './check-frequency';
|
|
30
|
+
const modalUseFrequencyConfig = createEventPromiseHandler<
|
|
31
|
+
IUseModalFrequencyConfig,
|
|
32
|
+
typeof UseModalFrequencyEventName
|
|
33
|
+
>(rewardsEmitter, UseModalFrequencyEventName);
|
|
34
|
+
|
|
35
|
+
modalUseFrequencyConfig.getData();
|
|
36
|
+
|
|
21
37
|
/**
|
|
22
38
|
* confirm jolicoin modal
|
|
23
39
|
*/
|
|
24
|
-
rewardsEmitter.on(UseModalEventName, (type: 'JOLI_COIN' | 'ADS-JOLI_COIN', params: IUseModalEvent) => {
|
|
40
|
+
rewardsEmitter.on(UseModalEventName, async (type: 'JOLI_COIN' | 'ADS-JOLI_COIN', params: IUseModalEvent) => {
|
|
25
41
|
if (type === 'ADS-JOLI_COIN') {
|
|
26
42
|
//TODO
|
|
27
43
|
console.log('use modal show by frequency');
|
|
44
|
+
const config = await modalUseFrequencyConfig.getData();
|
|
45
|
+
const canShowUseModal = await checkUseModalFrequency(config.joliCoinUseAndCharge.useJolicoin);
|
|
46
|
+
if (!canShowUseModal) {
|
|
47
|
+
// return by frequency control
|
|
48
|
+
rewardsEmitter.emit(UseModalResultEventName, { useModalResult: 'CONFIRM' });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
28
51
|
}
|
|
29
52
|
const modal = createConfirmJolicoinModal({
|
|
30
53
|
data: {
|
|
@@ -51,6 +74,8 @@ rewardsEmitter.on(UseModalEventName, (type: 'JOLI_COIN' | 'ADS-JOLI_COIN', param
|
|
|
51
74
|
}
|
|
52
75
|
}
|
|
53
76
|
});
|
|
77
|
+
|
|
78
|
+
await updateUseModalFrequency();
|
|
54
79
|
});
|
|
55
80
|
|
|
56
81
|
/**
|
|
@@ -63,6 +88,13 @@ rewardsEmitter.on(
|
|
|
63
88
|
// handle showup frequecy
|
|
64
89
|
if (type === 'ADS-JOLI_COIN') {
|
|
65
90
|
//
|
|
91
|
+
const config = await modalUseFrequencyConfig.getData();
|
|
92
|
+
const canShowPaymentModal = await checkPaymentFrequency(config.joliCoinUseAndCharge.charge);
|
|
93
|
+
if (!canShowPaymentModal) {
|
|
94
|
+
// return by frequency control
|
|
95
|
+
rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'SUCCESS' });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
66
98
|
console.log('show by frequency');
|
|
67
99
|
}
|
|
68
100
|
|
|
@@ -107,6 +139,8 @@ rewardsEmitter.on(
|
|
|
107
139
|
}
|
|
108
140
|
}
|
|
109
141
|
});
|
|
142
|
+
|
|
143
|
+
await updatePaymentFrequency();
|
|
110
144
|
} catch (error) {
|
|
111
145
|
console.info('payment failed', error);
|
|
112
146
|
rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'FAILED' });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const filterTodayTimestamps = (timestamps: number[]): number[] => {
|
|
2
|
+
const now = new Date();
|
|
3
|
+
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
|
|
4
|
+
const todayEnd = todayStart + 24 * 60 * 60 * 1000;
|
|
5
|
+
|
|
6
|
+
return timestamps.filter((timestamp) => timestamp >= todayStart && timestamp < todayEnd);
|
|
7
|
+
};
|