@jolibox/implement 1.1.25 → 1.1.26
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 +19 -14
- package/dist/common/context/index.d.ts +1 -0
- package/dist/common/context/url-parse.d.ts +1 -0
- package/dist/common/report/task-track/index.d.ts +1 -1
- package/dist/h5/api/base.d.ts +1 -1
- package/dist/h5/api/storage.d.ts +1 -1
- package/dist/index.js +8 -8
- package/dist/index.native.js +96 -99
- package/dist/native/api/base.d.ts +1 -1
- package/dist/native/api/keyboard.d.ts +3 -3
- package/dist/native/api/login.d.ts +1 -1
- package/dist/native/api/storage.d.ts +5 -5
- package/dist/native/payment/index.d.ts +4 -0
- package/dist/native/payment/payment-helper.d.ts +13 -0
- package/dist/native/payment/registers/base.d.ts +21 -0
- package/dist/native/payment/registers/joli-coin.d.ts +17 -0
- package/dist/native/payment/registers/type.d.ts +14 -0
- package/dist/native/report/task-tracker.d.ts +1 -1
- package/implement.build.log +2 -2
- package/package.json +5 -5
- package/src/common/context/index.ts +3 -0
- package/src/common/context/url-parse.ts +1 -0
- package/src/common/report/task-track/index.ts +3 -2
- package/src/common/rewards/registers/use-jolicoin-only.ts +4 -4
- package/src/common/rewards/registers/use-jolicoin.ts +4 -4
- package/src/h5/api/task.ts +43 -131
- package/src/native/api/ads.ts +4 -1
- package/src/native/api/storage.ts +9 -7
- package/src/native/api/task.ts +41 -159
- package/src/native/bootstrap/index.ts +2 -0
- package/src/native/payment/index.ts +5 -0
- package/src/native/payment/payment-helper.ts +44 -0
- package/src/native/payment/registers/base.ts +97 -0
- package/src/native/payment/registers/joli-coin.ts +83 -0
- package/src/native/payment/registers/type.ts +15 -0
- package/src/native/report/task-tracker.ts +1 -1
- package/src/native/rewards/check-frequency.ts +28 -15
- package/src/native/rewards/index.ts +8 -2
package/src/native/api/task.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createCommands } from '@jolibox/common';
|
|
2
|
-
|
|
3
2
|
import { createAPI, registerCanIUse, t } from './base';
|
|
4
3
|
import { taskTracker } from '../report';
|
|
5
4
|
|
|
@@ -7,20 +6,22 @@ const commands = createCommands();
|
|
|
7
6
|
|
|
8
7
|
const onLevelFinished = createAPI('levelFinished', {
|
|
9
8
|
paramsSchema: t.tuple(
|
|
10
|
-
t.string(),
|
|
11
9
|
t.object({
|
|
12
|
-
|
|
13
|
-
duration: t.number()
|
|
10
|
+
levelId: t.or(t.string(), t.number()),
|
|
11
|
+
duration: t.number().optional(),
|
|
12
|
+
rating: t.number().optional(),
|
|
13
|
+
score: t.number().optional()
|
|
14
14
|
})
|
|
15
15
|
),
|
|
16
|
-
implement: async (
|
|
17
|
-
const {
|
|
16
|
+
implement: async (parmas) => {
|
|
17
|
+
const { levelId, duration, rating, score } = parmas;
|
|
18
18
|
const tasks = [];
|
|
19
19
|
tasks.push(
|
|
20
20
|
taskTracker.tracker('LevelFinished', {
|
|
21
21
|
levelId,
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
duration,
|
|
23
|
+
rating,
|
|
24
|
+
score
|
|
24
25
|
})
|
|
25
26
|
);
|
|
26
27
|
|
|
@@ -33,195 +34,76 @@ const onLevelFinished = createAPI('levelFinished', {
|
|
|
33
34
|
}
|
|
34
35
|
});
|
|
35
36
|
|
|
36
|
-
const
|
|
37
|
+
const onGamePlayEnded = createAPI('gamePlayEnded', {
|
|
37
38
|
paramsSchema: t.tuple(
|
|
38
|
-
t.string(),
|
|
39
39
|
t.object({
|
|
40
|
-
duration: t.number()
|
|
40
|
+
duration: t.number().optional(),
|
|
41
|
+
rating: t.number().optional(),
|
|
42
|
+
score: t.number()
|
|
41
43
|
})
|
|
42
44
|
),
|
|
43
|
-
implement: async (
|
|
44
|
-
const { duration } = params;
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
taskId
|
|
50
|
-
}
|
|
45
|
+
implement: async (params) => {
|
|
46
|
+
const { duration, rating, score } = params;
|
|
47
|
+
return taskTracker.tracker('GamePlayEnded', {
|
|
48
|
+
duration,
|
|
49
|
+
rating,
|
|
50
|
+
score
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
const onLevelUpgrade = createAPI('levelUpgrade', {
|
|
56
|
-
paramsSchema: t.tuple(t.string(), t.string()),
|
|
57
|
-
implement: async (levelId, name) => {
|
|
58
|
-
const tasks = [];
|
|
59
|
-
tasks.push(
|
|
60
|
-
taskTracker.reportToNative({
|
|
61
|
-
event: 'LevelUpgrade',
|
|
62
|
-
params: {
|
|
63
|
-
name,
|
|
64
|
-
levelId
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
);
|
|
68
|
-
await Promise.all(tasks);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const onHistoryUserLevel = createAPI('onHistoryUserLevel', {
|
|
73
|
-
paramsSchema: t.tuple(t.number()),
|
|
74
|
-
implement: async (level) => {
|
|
75
|
-
return await taskTracker.reportToNative({
|
|
76
|
-
event: 'HistoryUserLevel',
|
|
77
|
-
params: {
|
|
78
|
-
level
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const onHistoryUserScore = createAPI('onHistoryUserScore', {
|
|
85
|
-
paramsSchema: t.tuple(t.number()),
|
|
86
|
-
implement: async (score) => {
|
|
87
|
-
return await taskTracker.reportToNative({
|
|
88
|
-
event: 'HistoryUserScore',
|
|
89
|
-
params: {
|
|
90
|
-
score
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const onTaskEvent = createAPI('taskEvent', {
|
|
97
56
|
paramsSchema: t.tuple(
|
|
98
|
-
t.string(),
|
|
99
57
|
t.object({
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
t.object({
|
|
103
|
-
id: t.string(),
|
|
104
|
-
name: t.string(),
|
|
105
|
-
count: t.number(),
|
|
106
|
-
description: t.string().optional(),
|
|
107
|
-
price: t
|
|
108
|
-
.object({
|
|
109
|
-
amount: t.number(),
|
|
110
|
-
unit: t.string()
|
|
111
|
-
})
|
|
112
|
-
.optional()
|
|
113
|
-
})
|
|
114
|
-
)
|
|
115
|
-
.optional(),
|
|
116
|
-
awards: t
|
|
117
|
-
.array(
|
|
118
|
-
t.object({
|
|
119
|
-
id: t.string(),
|
|
120
|
-
name: t.string()
|
|
121
|
-
})
|
|
122
|
-
)
|
|
123
|
-
.optional()
|
|
58
|
+
levelId: t.or(t.string(), t.number()),
|
|
59
|
+
name: t.string().optional()
|
|
124
60
|
})
|
|
125
61
|
),
|
|
126
|
-
implement: async (
|
|
62
|
+
implement: async ({ levelId, name }) => {
|
|
127
63
|
const tasks = [];
|
|
128
64
|
tasks.push(
|
|
129
|
-
taskTracker.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
taskId,
|
|
133
|
-
...params
|
|
134
|
-
}
|
|
65
|
+
taskTracker.tracker('LevelUpgrade', {
|
|
66
|
+
name,
|
|
67
|
+
levelId
|
|
135
68
|
})
|
|
136
69
|
);
|
|
137
|
-
// 使用了道具,上报任务
|
|
138
|
-
if (params.tools?.length ?? 0 > 0) {
|
|
139
|
-
tasks.push(
|
|
140
|
-
taskTracker.reporter({
|
|
141
|
-
event: 'USE_GAME_ITEM'
|
|
142
|
-
})
|
|
143
|
-
);
|
|
144
|
-
tasks.push(
|
|
145
|
-
taskTracker.reportToNative({
|
|
146
|
-
event: 'UseGameItem',
|
|
147
|
-
params: {
|
|
148
|
-
taskId,
|
|
149
|
-
...params
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
70
|
await Promise.all(tasks);
|
|
155
71
|
}
|
|
156
72
|
});
|
|
157
73
|
|
|
158
74
|
commands.registerCommand('TaskTrackerSDK.levelFinished', onLevelFinished);
|
|
159
|
-
commands.registerCommand('TaskTrackerSDK.
|
|
75
|
+
commands.registerCommand('TaskTrackerSDK.gamePlayEnded', onGamePlayEnded);
|
|
160
76
|
commands.registerCommand('TaskTrackerSDK.levelUpgrade', onLevelUpgrade);
|
|
161
|
-
commands.registerCommand('TaskTrackerSDK.historyUserLevel', onHistoryUserLevel);
|
|
162
|
-
commands.registerCommand('TaskTrackerSDK.historyUserScore', onHistoryUserScore);
|
|
163
|
-
commands.registerCommand('TaskTrackerSDK.taskEvent', onTaskEvent);
|
|
164
77
|
|
|
165
78
|
registerCanIUse('TaskTrackerSDK.onLevelFinished', {
|
|
166
|
-
version: '1.
|
|
79
|
+
version: '1.1.25',
|
|
167
80
|
properties: {
|
|
168
|
-
levelId: '1.0.0',
|
|
169
81
|
params: {
|
|
170
|
-
|
|
171
|
-
duration: '1.
|
|
82
|
+
levelId: '1.1.25',
|
|
83
|
+
duration: '1.1.25',
|
|
84
|
+
rating: '1.1.25',
|
|
85
|
+
score: '1.1.25'
|
|
172
86
|
}
|
|
173
87
|
}
|
|
174
88
|
});
|
|
175
89
|
|
|
176
|
-
registerCanIUse('TaskTrackerSDK.
|
|
177
|
-
version: '1.
|
|
90
|
+
registerCanIUse('TaskTrackerSDK.onGamePlayEnded', {
|
|
91
|
+
version: '1.1.25',
|
|
178
92
|
properties: {
|
|
179
|
-
|
|
180
|
-
|
|
93
|
+
params: {
|
|
94
|
+
duration: '1.1.25',
|
|
95
|
+
rating: '1.1.25',
|
|
96
|
+
score: '1.1.25'
|
|
97
|
+
}
|
|
181
98
|
}
|
|
182
99
|
});
|
|
183
100
|
|
|
184
101
|
registerCanIUse('TaskTrackerSDK.onLevelUpgrade', {
|
|
185
|
-
version: '1.
|
|
186
|
-
properties: {
|
|
187
|
-
levelId: '1.0.0',
|
|
188
|
-
name: '1.0.0'
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
registerCanIUse('TaskTrackerSDK.onHistoryUserLevel', {
|
|
193
|
-
version: '1.0.0',
|
|
194
|
-
properties: {
|
|
195
|
-
level: '1.0.0'
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
registerCanIUse('TaskTrackerSDK.onHistoryUserScore', {
|
|
200
|
-
version: '1.0.0',
|
|
201
|
-
properties: {
|
|
202
|
-
score: '1.0.0'
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
registerCanIUse('TaskTrackerSDK.onTaskEvent', {
|
|
207
|
-
version: '1.0.0',
|
|
102
|
+
version: '1.1.25',
|
|
208
103
|
properties: {
|
|
209
|
-
taskId: '1.0.0',
|
|
210
104
|
params: {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
name: '1.0.0',
|
|
214
|
-
count: '1.0.0',
|
|
215
|
-
description: '1.0.0',
|
|
216
|
-
price: {
|
|
217
|
-
amount: '1.0.0',
|
|
218
|
-
unit: '1.0.0'
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
awards: {
|
|
222
|
-
id: '1.0.0',
|
|
223
|
-
name: '1.0.0'
|
|
224
|
-
}
|
|
105
|
+
levelId: '1.1.25',
|
|
106
|
+
name: '1.1.25'
|
|
225
107
|
}
|
|
226
108
|
}
|
|
227
109
|
});
|
|
@@ -7,6 +7,7 @@ import { adEventEmitter } from '@/common/ads';
|
|
|
7
7
|
import { openRetentionSchema } from '../ui/retention';
|
|
8
8
|
import { innerFetch } from '../network';
|
|
9
9
|
import { Env } from '@jolibox/types';
|
|
10
|
+
import { registerLanguageHandler } from '@jolibox/ui';
|
|
10
11
|
import { createIframeModal, registerIframeModalToGlobal } from '../ui/modal-iframe';
|
|
11
12
|
interface IBasicMetaConfig {
|
|
12
13
|
canShowRecommended: boolean;
|
|
@@ -135,6 +136,7 @@ function addGameServiceReadyListener() {
|
|
|
135
136
|
|
|
136
137
|
// 任务上报
|
|
137
138
|
handleTaskTracker(loadDuration);
|
|
139
|
+
registerLanguageHandler(() => context.language);
|
|
138
140
|
});
|
|
139
141
|
|
|
140
142
|
onNative('onBeforeExit', ({ uuid }) => {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type PaymentType = 'JOLI_COIN'; // current only jolicoin
|
|
2
|
+
|
|
3
|
+
import { StandardResponse } from '@jolibox/types';
|
|
4
|
+
import { reportError } from '@/common/report/errors/report';
|
|
5
|
+
import { BaseError } from '@jolibox/common';
|
|
6
|
+
|
|
7
|
+
type PaymentResult = StandardResponse<void>;
|
|
8
|
+
|
|
9
|
+
export interface PaymentHandlerMap {
|
|
10
|
+
JOLI_COIN: (productId: string) => Promise<PaymentResult>; // jolicoin
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type PaymentHandler<T extends PaymentType> = PaymentHandlerMap[T];
|
|
14
|
+
|
|
15
|
+
export function createPaymentHelper() {
|
|
16
|
+
const paymentHandlers = new Map<PaymentType, PaymentHandler<any>>();
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
registerPaymentHandler<T extends PaymentType>(type: T, handler: PaymentHandler<T>) {
|
|
20
|
+
paymentHandlers.set(type, handler);
|
|
21
|
+
},
|
|
22
|
+
async invokePayment<T extends PaymentType>(type: T, ...args: Parameters<PaymentHandler<T>>) {
|
|
23
|
+
const paymentHandler = paymentHandlers.get(type);
|
|
24
|
+
if (!paymentHandler) {
|
|
25
|
+
return {
|
|
26
|
+
code: 'FAILED',
|
|
27
|
+
message: `[joliboxSDK]: ${type} payment not supported in this platform`
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const result = await paymentHandler(...args);
|
|
32
|
+
return result;
|
|
33
|
+
} catch (e) {
|
|
34
|
+
reportError(e as BaseError);
|
|
35
|
+
return {
|
|
36
|
+
code: 'FAILED',
|
|
37
|
+
message: `[joliboxSDK]: paymenterror ${e}`
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type PaymentHelper = ReturnType<typeof createPaymentHelper>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { StandardResponse } from '@jolibox/types';
|
|
2
|
+
import type { IPlaceOrderJoliCoinParamas, IJoliCoinProductInfo, IJolicoinPaymentContext } from './joli-coin';
|
|
3
|
+
import type { IPlaceOrderResponse } from './type';
|
|
4
|
+
import { PaymentErrorCodeMap } from './type';
|
|
5
|
+
type PaymentStatus = 'INIT' | 'PENDING' | 'SUCCESS' | 'FAILED';
|
|
6
|
+
import { UserPaymentError, InternalPaymentError } from '@jolibox/common';
|
|
7
|
+
import { context } from '@/common/context';
|
|
8
|
+
import { innerFetch as fetch } from '@/native/network';
|
|
9
|
+
|
|
10
|
+
type IPlaceOrderParams = IPlaceOrderJoliCoinParamas;
|
|
11
|
+
type IOrderProductInfo = IJoliCoinProductInfo;
|
|
12
|
+
type IOrderPaymentContext = IJolicoinPaymentContext;
|
|
13
|
+
|
|
14
|
+
const createPaymentErrorFactory = () => {
|
|
15
|
+
const [createPaymentError, createPaymentInternalError] = [UserPaymentError, InternalPaymentError].map(
|
|
16
|
+
(ctor) => {
|
|
17
|
+
return (errMsg: string, errNo: number, extra?: Record<string, unknown>) => {
|
|
18
|
+
return new ctor(errMsg, errNo, extra);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
return {
|
|
23
|
+
createPaymentError,
|
|
24
|
+
createPaymentInternalError
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const { createPaymentError, createPaymentInternalError } = createPaymentErrorFactory();
|
|
29
|
+
export { createPaymentError, createPaymentInternalError };
|
|
30
|
+
|
|
31
|
+
const CALLBACK_HOST = context.testMode ? 'https://stg-game.jolibox.com' : 'https://game.jolibox.com';
|
|
32
|
+
|
|
33
|
+
export abstract class BasePaymentRegister<T extends IPlaceOrderParams, E extends IOrderProductInfo> {
|
|
34
|
+
private _orderId: string | null = null;
|
|
35
|
+
private _orderStatus: PaymentStatus = 'INIT';
|
|
36
|
+
|
|
37
|
+
startPayment = async (params: T) => {
|
|
38
|
+
if (this._orderId) {
|
|
39
|
+
await this.cancelOrder(this.orderId as string);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { data, code, message } = await this.placeOrder(params);
|
|
43
|
+
if (code !== 'SUCCESS' || !data || !data.orderId) {
|
|
44
|
+
throw createPaymentError(message, PaymentErrorCodeMap.PlaceOrderFailed);
|
|
45
|
+
}
|
|
46
|
+
if (data?.status !== 'PENDING') {
|
|
47
|
+
throw createPaymentInternalError(
|
|
48
|
+
`Place order failed, status: ${data?.status}`,
|
|
49
|
+
PaymentErrorCodeMap.PlaceOrderFailed
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { orderId } = data;
|
|
54
|
+
this._orderId = orderId;
|
|
55
|
+
// invoke native payment;
|
|
56
|
+
|
|
57
|
+
const callbackUrl = this.generateCallbackUrl();
|
|
58
|
+
// 回调页
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
cancelOrder = async (orderId: string) => {
|
|
62
|
+
const { response } = await fetch(`/api/orders/${orderId}/cancel`, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
data: {}
|
|
65
|
+
});
|
|
66
|
+
if (response.code !== 'SUCCCESS') {
|
|
67
|
+
throw createPaymentError(
|
|
68
|
+
response.message ?? response.errMsg ?? '',
|
|
69
|
+
PaymentErrorCodeMap.CancelOrderFailed
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
private generateCallbackUrl = () => {
|
|
75
|
+
// Set or replace gameId and joliSource parameters
|
|
76
|
+
const originalSearch = new URLSearchParams('');
|
|
77
|
+
originalSearch.set('utm_source', context.deviceInfo.platform);
|
|
78
|
+
originalSearch.set(
|
|
79
|
+
'joliSource',
|
|
80
|
+
context.encodeJoliSourceQuery({
|
|
81
|
+
...this.generatePaymentContext()
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
return `${CALLBACK_HOST}//payment/callback?${originalSearch.toString()}`;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
abstract placeOrder(params: T): Promise<StandardResponse<IPlaceOrderResponse<E>>>;
|
|
88
|
+
abstract generatePaymentContext(): IOrderPaymentContext;
|
|
89
|
+
|
|
90
|
+
get orderId(): string | null {
|
|
91
|
+
return this._orderId;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get status(): PaymentStatus {
|
|
95
|
+
return this._orderStatus;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { innerFetch as fetch } from '@/native/network';
|
|
2
|
+
import { BasePaymentRegister, createPaymentError, createPaymentInternalError } from './base';
|
|
3
|
+
import { PaymentErrorCodeMap, IPlaceOrderResponse } from './type';
|
|
4
|
+
import { ResponseType, StandardResponse } from '@jolibox/types';
|
|
5
|
+
|
|
6
|
+
export interface IPlaceOrderJoliCoinParamas {
|
|
7
|
+
productId: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface IJoliCoinProductInfo {
|
|
11
|
+
quantity: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IJolicoinPaymentContext {
|
|
15
|
+
type: 'JOLI_COIN_ORDER_CONTEXT';
|
|
16
|
+
state: 'TO_CHECKOUT' | 'TO_VALIDATE';
|
|
17
|
+
productId: string;
|
|
18
|
+
orderId: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class JolicoinPaymentResiter extends BasePaymentRegister<IPlaceOrderJoliCoinParamas, IJoliCoinProductInfo> {
|
|
22
|
+
constructor(readonly productId: string) {
|
|
23
|
+
super();
|
|
24
|
+
}
|
|
25
|
+
async placeOrder(
|
|
26
|
+
params: IPlaceOrderJoliCoinParamas
|
|
27
|
+
): Promise<StandardResponse<IPlaceOrderResponse<IJoliCoinProductInfo>, unknown>> {
|
|
28
|
+
try {
|
|
29
|
+
const { response } = await fetch<IPlaceOrderResponse<IJoliCoinProductInfo>>(
|
|
30
|
+
'/api/orders/checkout/joli-coin',
|
|
31
|
+
{
|
|
32
|
+
method: 'POST',
|
|
33
|
+
data: { productId: params.productId }
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (response.code !== 'SUCCESS') {
|
|
38
|
+
throw createPaymentError(
|
|
39
|
+
response.errMsg ?? response.message ?? '',
|
|
40
|
+
PaymentErrorCodeMap.JolicoinPlaceOrderRequestFailed
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
code: 'SUCCESS' as ResponseType,
|
|
46
|
+
message: response.message ?? 'placeorder jolicoin success',
|
|
47
|
+
data: response.data
|
|
48
|
+
};
|
|
49
|
+
} catch (e) {
|
|
50
|
+
console.info(`[JoliboxSDK] placeorder failed`, e);
|
|
51
|
+
throw createPaymentInternalError(
|
|
52
|
+
JSON.stringify(e) ?? 'jolicoin placeorder failed',
|
|
53
|
+
PaymentErrorCodeMap.JolicoinPlaceOrderRequestFailed
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
generatePaymentContext = (): IJolicoinPaymentContext => {
|
|
59
|
+
return {
|
|
60
|
+
type: 'JOLI_COIN_ORDER_CONTEXT',
|
|
61
|
+
state: 'TO_VALIDATE',
|
|
62
|
+
productId: this.productId,
|
|
63
|
+
orderId: this.orderId!
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const createJolicoinPaymentHandler = () => {
|
|
69
|
+
const productPaymentMap = new Map<string, JolicoinPaymentResiter>();
|
|
70
|
+
return async (productId: string) => {
|
|
71
|
+
let instance = productPaymentMap.get(productId);
|
|
72
|
+
if (!instance) {
|
|
73
|
+
instance = new JolicoinPaymentResiter(productId);
|
|
74
|
+
productPaymentMap.set(productId, instance);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await instance.startPayment({ productId });
|
|
78
|
+
return {
|
|
79
|
+
code: 'SUCCESS' as ResponseType,
|
|
80
|
+
message: 'jolicoin payment success'
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type OrderStatus = 'PENDING' | 'PAYING' | 'PAYMENT_FAILED' | 'PAYMENT_SUCCESS' | 'PAYMENT_CLOSED';
|
|
2
|
+
|
|
3
|
+
export interface IPlaceOrderResponse<T> {
|
|
4
|
+
orderId: string;
|
|
5
|
+
status: OrderStatus;
|
|
6
|
+
totalAmountStr: string;
|
|
7
|
+
joliBizType: 'DRAMA' | 'JOLI_COIN';
|
|
8
|
+
productInfo: T;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export enum PaymentErrorCodeMap {
|
|
12
|
+
PlaceOrderFailed = 1001,
|
|
13
|
+
JolicoinPlaceOrderRequestFailed = 1002,
|
|
14
|
+
CancelOrderFailed = 1003
|
|
15
|
+
}
|
|
@@ -2,6 +2,16 @@ import { StandardResponse } from '@jolibox/types';
|
|
|
2
2
|
import { getGlobalStorage, setGlobalStorage } from '../api/storage';
|
|
3
3
|
import { filterTodayTimestamps } from './utils';
|
|
4
4
|
|
|
5
|
+
const parseFrequency = (data: string) => {
|
|
6
|
+
let fequeycies;
|
|
7
|
+
try {
|
|
8
|
+
fequeycies = JSON.parse(data);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
fequeycies = [];
|
|
11
|
+
}
|
|
12
|
+
return fequeycies;
|
|
13
|
+
};
|
|
14
|
+
|
|
5
15
|
/**
|
|
6
16
|
* check can show useModal
|
|
7
17
|
* @param config
|
|
@@ -9,11 +19,12 @@ import { filterTodayTimestamps } from './utils';
|
|
|
9
19
|
*/
|
|
10
20
|
export const checkUseModalFrequency = async (config: { dailyMaxPopUps: number; minInterval: number }) => {
|
|
11
21
|
const { dailyMaxPopUps, minInterval } = config;
|
|
12
|
-
const res = (await getGlobalStorage('joli_coin_use_modal_frequency')) as StandardResponse<
|
|
22
|
+
const res = (await getGlobalStorage('joli_coin_use_modal_frequency')) as StandardResponse<string>;
|
|
13
23
|
if (!res.data) {
|
|
14
24
|
return true;
|
|
15
25
|
}
|
|
16
|
-
|
|
26
|
+
|
|
27
|
+
const fequeycies = parseFrequency(res.data);
|
|
17
28
|
const todayFequencies = filterTodayTimestamps(fequeycies);
|
|
18
29
|
if (todayFequencies.length >= dailyMaxPopUps) {
|
|
19
30
|
return false;
|
|
@@ -27,12 +38,13 @@ export const checkUseModalFrequency = async (config: { dailyMaxPopUps: number; m
|
|
|
27
38
|
|
|
28
39
|
export const updateUseModalFrequency = async () => {
|
|
29
40
|
const now = Date.now();
|
|
30
|
-
const res = (await getGlobalStorage('joli_coin_use_modal_frequency')) as StandardResponse<
|
|
41
|
+
const res = (await getGlobalStorage('joli_coin_use_modal_frequency')) as StandardResponse<string>;
|
|
31
42
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
const frequencies = parseFrequency(res.data ?? '[]') as number[];
|
|
44
|
+
frequencies.push(now);
|
|
45
|
+
frequencies.sort((a, b) => b - a).splice(8);
|
|
46
|
+
|
|
47
|
+
await setGlobalStorage('joli_coin_use_modal_frequency', JSON.stringify(frequencies));
|
|
36
48
|
};
|
|
37
49
|
|
|
38
50
|
/**
|
|
@@ -40,13 +52,13 @@ export const updateUseModalFrequency = async () => {
|
|
|
40
52
|
*/
|
|
41
53
|
export const checkPaymentFrequency = async (config: { dailyMaxPopUps: number; minInterval: number }) => {
|
|
42
54
|
const { dailyMaxPopUps, minInterval } = config;
|
|
43
|
-
const res = (await getGlobalStorage('joli_coin_payment_frequency')) as StandardResponse<
|
|
55
|
+
const res = (await getGlobalStorage('joli_coin_payment_frequency')) as StandardResponse<string>;
|
|
44
56
|
|
|
45
57
|
if (!res.data) {
|
|
46
58
|
return true;
|
|
47
59
|
}
|
|
48
|
-
const
|
|
49
|
-
const todayFequencies = filterTodayTimestamps(
|
|
60
|
+
const frequencies = parseFrequency(res.data);
|
|
61
|
+
const todayFequencies = filterTodayTimestamps(frequencies);
|
|
50
62
|
if (todayFequencies.length >= dailyMaxPopUps) {
|
|
51
63
|
return false;
|
|
52
64
|
}
|
|
@@ -62,9 +74,10 @@ export const checkPaymentFrequency = async (config: { dailyMaxPopUps: number; mi
|
|
|
62
74
|
*/
|
|
63
75
|
export const updatePaymentFrequency = async () => {
|
|
64
76
|
const now = Date.now();
|
|
65
|
-
const res = (await getGlobalStorage('joli_coin_payment_frequency')) as StandardResponse<
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
const res = (await getGlobalStorage('joli_coin_payment_frequency')) as StandardResponse<string>;
|
|
78
|
+
const fequeycies: number[] = parseFrequency(res.data ?? '[]');
|
|
79
|
+
|
|
80
|
+
fequeycies.push(now);
|
|
81
|
+
fequeycies.sort((a, b) => b - a).splice(8);
|
|
82
|
+
await setGlobalStorage('joli_coin_payment_frequency', JSON.stringify(fequeycies));
|
|
70
83
|
};
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
checkPaymentFrequency,
|
|
28
28
|
updatePaymentFrequency
|
|
29
29
|
} from './check-frequency';
|
|
30
|
+
import { paymentHelper } from '../payment';
|
|
30
31
|
|
|
31
32
|
const modalUseFrequencyConfig = createEventPromiseHandler<
|
|
32
33
|
IUseModalFrequencyConfig,
|
|
@@ -153,14 +154,19 @@ rewardsEmitter.on(
|
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
const balenceDetails = await getBalenceDetails();
|
|
156
|
-
if ((balenceDetails?.balance ?? 0) >= params.joliCoinQuantity
|
|
157
|
+
if ((balenceDetails?.balance ?? 0) >= params.joliCoinQuantity) {
|
|
157
158
|
rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'SUCCESS' });
|
|
158
159
|
modal.destroy();
|
|
159
160
|
return;
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
163
|
console.log('invokeNativePayment', productId);
|
|
163
|
-
|
|
164
|
+
const { code } = await paymentHelper.invokePayment('JOLI_COIN', productId);
|
|
165
|
+
if (code !== 'SUCCESS') {
|
|
166
|
+
rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'FAILED' });
|
|
167
|
+
modal.destroy();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
164
170
|
rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'SUCCESS' });
|
|
165
171
|
modal.destroy();
|
|
166
172
|
}
|