@jolibox/implement 1.2.3 → 1.2.5-beta.3
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 +44 -28
- package/.rush/temp/shrinkwrap-deps.json +2 -1
- package/CHANGELOG.json +11 -0
- package/CHANGELOG.md +9 -0
- package/dist/common/context/index.d.ts +5 -0
- package/dist/common/report/base-tracker.d.ts +2 -1
- package/dist/common/rewards/cached-fetch-reward.d.ts +46 -0
- package/dist/common/rewards/cached-reward-service.d.ts +24 -0
- package/dist/common/rewards/fetch-reward.d.ts +2 -3
- package/dist/common/rewards/index.d.ts +3 -0
- package/dist/common/rewards/registers/use-subscription.d.ts +7 -0
- package/dist/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.d.ts +34 -0
- package/dist/common/rewards/registers/utils/coins/jolicoin/fetch-balance.d.ts +2 -1
- package/dist/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.d.ts +34 -0
- package/dist/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.d.ts +2 -1
- package/dist/common/rewards/registers/utils/subscription/commands/index.d.ts +1 -0
- package/dist/common/rewards/registers/utils/subscription/commands/use-subscription.d.ts +4 -0
- package/dist/common/rewards/registers/utils/subscription/sub-handler.d.ts +13 -0
- package/dist/common/rewards/reward-emitter.d.ts +7 -0
- package/dist/common/rewards/reward-helper.d.ts +2 -1
- package/dist/common/utils/index.d.ts +18 -0
- package/dist/h5/api/platformAdsHandle/JoliboxAdsHandler.d.ts +1 -0
- package/dist/h5/bootstrap/auth/__tests__/auth.test.d.ts +1 -0
- package/dist/h5/bootstrap/auth/index.d.ts +2 -0
- package/dist/h5/bootstrap/auth/sub.d.ts +2 -0
- package/dist/index.js +9 -13
- package/dist/index.native.js +49 -53
- package/dist/native/api/index.d.ts +1 -0
- package/dist/native/api/payment.d.ts +1 -0
- package/dist/native/payment/__tests__/payment-service-simple.test.d.ts +1 -0
- package/dist/native/payment/payment-helper.d.ts +8 -5
- package/dist/native/payment/payment-service.d.ts +44 -0
- package/implement.build.log +2 -2
- package/package.json +8 -7
- package/src/common/context/index.ts +12 -0
- package/src/common/report/base-tracker.ts +2 -2
- package/src/common/rewards/cached-fetch-reward.ts +258 -0
- package/src/common/rewards/cached-reward-service.ts +255 -0
- package/src/common/rewards/fetch-reward.ts +17 -93
- package/src/common/rewards/index.ts +4 -0
- package/src/common/rewards/registers/use-subscription.ts +34 -0
- package/src/common/rewards/registers/utils/coins/jolicoin/cached-fetch-balance.ts +177 -0
- package/src/common/rewards/registers/utils/coins/jolicoin/fetch-balance.ts +13 -1
- package/src/common/rewards/registers/utils/coins/jolicoin/jolicoin-handler.ts +2 -0
- package/src/common/rewards/registers/utils/coins/joligem/cached-fetch-gem-balance.ts +181 -0
- package/src/common/rewards/registers/utils/coins/joligem/fetch-gem-balance.ts +13 -1
- package/src/common/rewards/registers/utils/coins/joligem/gem-handler.ts +2 -0
- package/src/common/rewards/registers/utils/subscription/commands/index.ts +1 -0
- package/src/common/rewards/registers/utils/subscription/commands/use-subscription.ts +29 -0
- package/src/common/rewards/registers/utils/subscription/sub-handler.ts +88 -0
- package/src/common/rewards/reward-emitter.ts +8 -0
- package/src/common/rewards/reward-helper.ts +8 -1
- package/src/common/utils/index.ts +23 -0
- package/src/h5/api/ads.ts +18 -12
- package/src/h5/api/platformAdsHandle/JoliboxAdsHandler.ts +25 -1
- package/src/h5/api/storage.ts +2 -2
- package/src/h5/bootstrap/auth/__tests__/auth.test.ts +308 -0
- package/src/h5/bootstrap/auth/index.ts +20 -0
- package/src/h5/bootstrap/auth/sub.ts +56 -0
- package/src/h5/bootstrap/index.ts +4 -19
- package/src/h5/http/index.ts +2 -2
- package/src/h5/report/event-tracker.ts +2 -2
- package/src/h5/rewards/index.ts +18 -1
- package/src/native/api/ads.ts +7 -1
- package/src/native/api/call-host-method.ts +1 -1
- package/src/native/api/index.ts +1 -0
- package/src/native/api/navigate.ts +10 -1
- package/src/native/api/payment.ts +56 -0
- package/src/native/payment/__tests__/payment-service-simple.test.ts +274 -0
- package/src/native/payment/payment-helper.ts +10 -4
- package/src/native/payment/payment-service.ts +293 -0
- package/src/native/payment/registers/jolicoin-iap.ts +4 -4
- package/src/native/report/index.ts +4 -1
- package/src/native/rewards/ui/payment-modal.ts +20 -60
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { IPaymentChoice } from '@/common/rewards/reward-emitter';
|
|
2
|
+
import { paymentHelper } from './index';
|
|
3
|
+
import { isUndefinedOrNull } from '@jolibox/common';
|
|
4
|
+
import { StandardResponse } from '@jolibox/types';
|
|
5
|
+
import { applyNative } from '@jolibox/native-bridge';
|
|
6
|
+
import { innerFetch as fetch } from '@/native/network';
|
|
7
|
+
import type { PaymentResult } from './payment-helper';
|
|
8
|
+
import { RequestCacheService, RequestAdapter } from '@jolibox/common';
|
|
9
|
+
|
|
10
|
+
type PaymentPurchaseType = 'JOLI_COIN' | 'JOLI_GEM';
|
|
11
|
+
|
|
12
|
+
// Request/Response interfaces for RequestCacheService
|
|
13
|
+
|
|
14
|
+
type PaymentRequest = Record<string, never>;
|
|
15
|
+
|
|
16
|
+
interface PaymentResponse {
|
|
17
|
+
balance: number;
|
|
18
|
+
enableAutoDeduct: boolean;
|
|
19
|
+
paymentChoices: IPaymentChoice[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface PaymentCacheData {
|
|
23
|
+
paymentChoices: IPaymentChoice[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface PaymentRealTimeData {
|
|
27
|
+
balance: number;
|
|
28
|
+
enableAutoDeduct: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Utility function for merging response data
|
|
32
|
+
function mergeResponseData(
|
|
33
|
+
responseData: { paymentChoices: IPaymentChoice[] },
|
|
34
|
+
data: { [appStoreProductId: string]: { price: string } }
|
|
35
|
+
) {
|
|
36
|
+
Object.keys(data).forEach((key) => {
|
|
37
|
+
const choice = responseData.paymentChoices.find((choice) => choice.appStoreProductId === key);
|
|
38
|
+
if (choice) {
|
|
39
|
+
choice.totalAmountStr = data[key].price;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
responseData.paymentChoices = responseData.paymentChoices.filter(
|
|
44
|
+
(choice) => !isUndefinedOrNull(choice.totalAmountStr)
|
|
45
|
+
) as IPaymentChoice[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Payment Request Adapter for RequestCacheService
|
|
49
|
+
class PaymentRequestAdapter
|
|
50
|
+
implements RequestAdapter<PaymentRequest, PaymentResponse, PaymentCacheData, PaymentRealTimeData>
|
|
51
|
+
{
|
|
52
|
+
// applyNative 的缓存
|
|
53
|
+
private static nativePriceCache = new Map<string, { [appStoreProductId: string]: { price: string } }>();
|
|
54
|
+
private static readonly NATIVE_PRICE_CACHE_DURATION = 30 * 60 * 1000; // 30分钟缓存
|
|
55
|
+
private static nativePriceCacheTimestamp = new Map<string, number>();
|
|
56
|
+
|
|
57
|
+
async execute(endpoint: string, _options?: PaymentRequest): Promise<PaymentResponse> {
|
|
58
|
+
// 获取服务端数据(余额等实时数据)
|
|
59
|
+
const { response } = await fetch<StandardResponse<PaymentResponse>>(endpoint, {
|
|
60
|
+
method: 'GET',
|
|
61
|
+
appendHostCookie: true,
|
|
62
|
+
responseType: 'json'
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log('[PaymentService] get products info from server', endpoint, response.data);
|
|
66
|
+
|
|
67
|
+
if (!response.data?.data) {
|
|
68
|
+
throw new Error('get products info failed');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const serverData = response.data.data;
|
|
72
|
+
|
|
73
|
+
const appStoreProductIds =
|
|
74
|
+
serverData.paymentChoices
|
|
75
|
+
?.filter((choice) => typeof choice.appStoreProductId === 'string')
|
|
76
|
+
.map((choice) => choice.appStoreProductId as string) ?? [];
|
|
77
|
+
|
|
78
|
+
if (appStoreProductIds.length > 0) {
|
|
79
|
+
const nativeData = await this.getNativePriceData(appStoreProductIds);
|
|
80
|
+
if (nativeData) {
|
|
81
|
+
mergeResponseData(serverData, nativeData);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (serverData.paymentChoices.length === 0) {
|
|
86
|
+
throw new Error('paymentChoices is empty');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return serverData;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private async getNativePriceData(
|
|
93
|
+
appStoreProductIds: string[]
|
|
94
|
+
): Promise<{ [appStoreProductId: string]: { price: string } } | null> {
|
|
95
|
+
// 检查缓存
|
|
96
|
+
const cacheKey = appStoreProductIds.sort().join(',');
|
|
97
|
+
const cached = PaymentRequestAdapter.nativePriceCache.get(cacheKey);
|
|
98
|
+
const cacheTime = PaymentRequestAdapter.nativePriceCacheTimestamp.get(cacheKey) || 0;
|
|
99
|
+
|
|
100
|
+
if (cached && Date.now() - cacheTime < PaymentRequestAdapter.NATIVE_PRICE_CACHE_DURATION) {
|
|
101
|
+
console.log('[PaymentService] Using cached native price data');
|
|
102
|
+
return cached;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.log('[PaymentService] Fetching fresh native price data');
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const { data } = await applyNative('requestProductDetailsAsync', {
|
|
109
|
+
appStoreProductIds
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (data) {
|
|
113
|
+
// cache
|
|
114
|
+
PaymentRequestAdapter.nativePriceCache.set(cacheKey, data);
|
|
115
|
+
PaymentRequestAdapter.nativePriceCacheTimestamp.set(cacheKey, Date.now());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return data;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.warn('[PaymentService] Failed to fetch native product details:', error);
|
|
121
|
+
throw error; // rethrow error, let upper layer handle it
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
extractCacheableData(response: PaymentResponse): PaymentCacheData {
|
|
126
|
+
return {
|
|
127
|
+
paymentChoices: response.paymentChoices
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
extractRealTimeData?: undefined;
|
|
132
|
+
mergeData(cached: PaymentCacheData, realTime: PaymentRealTimeData): PaymentResponse {
|
|
133
|
+
return {
|
|
134
|
+
balance: realTime.balance,
|
|
135
|
+
enableAutoDeduct: realTime.enableAutoDeduct,
|
|
136
|
+
paymentChoices: cached.paymentChoices
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
processCachedData(cached: PaymentCacheData): PaymentResponse {
|
|
141
|
+
// when only cached data is available, use default real-time data values
|
|
142
|
+
return {
|
|
143
|
+
balance: 0, // default balance
|
|
144
|
+
enableAutoDeduct: false, // default not enable auto deduct
|
|
145
|
+
paymentChoices: cached.paymentChoices
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// clear native price cache static method
|
|
150
|
+
static clearNativePriceCache(): void {
|
|
151
|
+
this.nativePriceCache.clear();
|
|
152
|
+
this.nativePriceCacheTimestamp.clear();
|
|
153
|
+
console.log('[PaymentService] Cleared native price cache');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Base Payment Service class
|
|
158
|
+
class BasePaymentService extends RequestCacheService<
|
|
159
|
+
PaymentRequest,
|
|
160
|
+
PaymentResponse,
|
|
161
|
+
PaymentCacheData,
|
|
162
|
+
PaymentRealTimeData
|
|
163
|
+
> {
|
|
164
|
+
// 失败计数器,按 endpoint 统计
|
|
165
|
+
private static failureCounters = new Map<string, number>();
|
|
166
|
+
private static readonly MAX_FAILURE_COUNT = 2;
|
|
167
|
+
|
|
168
|
+
constructor(private apiEndpoint: string, private paymentType: PaymentPurchaseType) {
|
|
169
|
+
super(new PaymentRequestAdapter(), {
|
|
170
|
+
duration: 10 * 60 * 1000, // 10分钟缓存 paymentChoices
|
|
171
|
+
timeout: 1000 // 1秒超时
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async getProductsInfo(): Promise<PaymentResponse | undefined> {
|
|
176
|
+
// 检查失败计数,如果达到最大失败次数则直接抛出错误
|
|
177
|
+
const currentFailureCount = BasePaymentService.failureCounters.get(this.apiEndpoint) || 0;
|
|
178
|
+
if (currentFailureCount >= BasePaymentService.MAX_FAILURE_COUNT) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`getProductsInfo has failed more than ${BasePaymentService.MAX_FAILURE_COUNT} times for ${this.apiEndpoint}`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const result = await this.request(this.apiEndpoint);
|
|
186
|
+
// 成功时重置失败计数器
|
|
187
|
+
BasePaymentService.failureCounters.delete(this.apiEndpoint);
|
|
188
|
+
return result;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
// 失败时增加计数器
|
|
191
|
+
const newCount = currentFailureCount + 1;
|
|
192
|
+
BasePaymentService.failureCounters.set(this.apiEndpoint, newCount);
|
|
193
|
+
console.warn(
|
|
194
|
+
`[PaymentService] getProductsInfo failed (${newCount}/${
|
|
195
|
+
BasePaymentService.MAX_FAILURE_COUNT + 1
|
|
196
|
+
}) for ${this.apiEndpoint}:`,
|
|
197
|
+
error
|
|
198
|
+
);
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async purchase(productId: string): Promise<PaymentResult<{ totalAmount: string }>> {
|
|
204
|
+
const productsInfo = await this.getProductsInfo();
|
|
205
|
+
const appStoreProductId = productsInfo?.paymentChoices.find(
|
|
206
|
+
(choice) => choice.productId === productId
|
|
207
|
+
)?.appStoreProductId;
|
|
208
|
+
if (!appStoreProductId) {
|
|
209
|
+
throw new Error('appStoreProductId not found');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const result = (await paymentHelper.invokePayment(
|
|
213
|
+
this.paymentType === 'JOLI_COIN' ? 'JOLI_COIN_IAP' : 'JOLI_GEM_IAP',
|
|
214
|
+
{
|
|
215
|
+
productId,
|
|
216
|
+
appStoreProductId
|
|
217
|
+
}
|
|
218
|
+
)) as PaymentResult<{ totalAmount: string }>;
|
|
219
|
+
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// 获取产品信息(使用 RequestCacheService)
|
|
224
|
+
async getProductsInfoWithBalance(): Promise<PaymentResponse | undefined> {
|
|
225
|
+
return this.request(this.apiEndpoint);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 强制刷新产品信息
|
|
229
|
+
async refreshProductsInfo(): Promise<PaymentResponse | undefined> {
|
|
230
|
+
return this.forceRequest(this.apiEndpoint);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// 重置失败计数器(供测试使用)
|
|
234
|
+
static resetFailureCounters(): void {
|
|
235
|
+
this.failureCounters.clear();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 获取失败计数器状态(供测试使用)
|
|
239
|
+
static getFailureCount(endpoint: string): number {
|
|
240
|
+
return this.failureCounters.get(endpoint) || 0;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// JOLI_COIN payment service
|
|
245
|
+
export class JoliCoinPaymentService extends BasePaymentService {
|
|
246
|
+
constructor() {
|
|
247
|
+
super('/api/joli-coin/balance-detail', 'JOLI_COIN');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// JOLI_GEM payment service
|
|
252
|
+
export class JoliGemPaymentService extends BasePaymentService {
|
|
253
|
+
constructor() {
|
|
254
|
+
super('/api/joli-gem/balance-detail', 'JOLI_GEM');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// service instance management
|
|
259
|
+
let joliCoinServiceInstance: JoliCoinPaymentService | null = null;
|
|
260
|
+
let joliGemServiceInstance: JoliGemPaymentService | null = null;
|
|
261
|
+
|
|
262
|
+
// create JOLI_COIN payment service instance
|
|
263
|
+
export const createJoliCoinPaymentService = (): JoliCoinPaymentService => {
|
|
264
|
+
if (joliCoinServiceInstance) {
|
|
265
|
+
return joliCoinServiceInstance;
|
|
266
|
+
}
|
|
267
|
+
joliCoinServiceInstance = new JoliCoinPaymentService();
|
|
268
|
+
return joliCoinServiceInstance;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// create JOLI_GEM payment service instance
|
|
272
|
+
export const createJoliGemPaymentService = (): JoliGemPaymentService => {
|
|
273
|
+
if (joliGemServiceInstance) {
|
|
274
|
+
return joliGemServiceInstance;
|
|
275
|
+
}
|
|
276
|
+
joliGemServiceInstance = new JoliGemPaymentService();
|
|
277
|
+
return joliGemServiceInstance;
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// 导出原生价格缓存清理方法供测试使用
|
|
281
|
+
export const clearNativePriceCache = (): void => {
|
|
282
|
+
PaymentRequestAdapter.clearNativePriceCache();
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// 导出失败计数器重置方法供测试使用
|
|
286
|
+
export const resetFailureCounters = (): void => {
|
|
287
|
+
BasePaymentService.resetFailureCounters();
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// 导出获取失败计数方法供测试使用
|
|
291
|
+
export const getFailureCount = (endpoint: string): number => {
|
|
292
|
+
return BasePaymentService.getFailureCount(endpoint);
|
|
293
|
+
};
|
|
@@ -75,7 +75,7 @@ onNative('onPaymentStateChange', (data) => {
|
|
|
75
75
|
pendingPayments.delete(orderUUID);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
const
|
|
78
|
+
const purchaseGem = async (params: { appStoreProductId: string; appAccountToken?: string }) => {
|
|
79
79
|
const deferred = new Deferred<StandardResponse<{ totalAmount: string }>>();
|
|
80
80
|
let targetOrderUUID: string | undefined;
|
|
81
81
|
|
|
@@ -88,7 +88,7 @@ const payInApp = async (params: { appStoreProductId: string; appAccountToken?: s
|
|
|
88
88
|
});
|
|
89
89
|
targetOrderUUID = response.data?.orderUUID;
|
|
90
90
|
|
|
91
|
-
console.info('---
|
|
91
|
+
console.info('---purchaseGem---', response);
|
|
92
92
|
if (!targetOrderUUID) {
|
|
93
93
|
throw createPaymentInternalError(
|
|
94
94
|
'orderUUID is null',
|
|
@@ -134,7 +134,7 @@ class JolicoinIAPAndroidPaymentResiter extends BasePaymentRegister<
|
|
|
134
134
|
};
|
|
135
135
|
|
|
136
136
|
pay = async (): Promise<StandardResponse<{ totalAmount: string }>> => {
|
|
137
|
-
return await
|
|
137
|
+
return await purchaseGem({ appStoreProductId: this.appStoreProductId });
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -180,7 +180,7 @@ class JolicoinIAPIOSPaymentResiter extends BasePaymentRegister<
|
|
|
180
180
|
};
|
|
181
181
|
|
|
182
182
|
pay = async (): Promise<StandardResponse<{ totalAmount: string }>> => {
|
|
183
|
-
return await
|
|
183
|
+
return await purchaseGem({
|
|
184
184
|
appStoreProductId: this.appStoreProductId,
|
|
185
185
|
appAccountToken: this.appAccountToken
|
|
186
186
|
});
|
|
@@ -13,12 +13,15 @@ const reportNative: ReportHandler = (event, data, webviewId) => {
|
|
|
13
13
|
: isString(_data.extra)
|
|
14
14
|
? JSON.parse(_data.extra)
|
|
15
15
|
: {};
|
|
16
|
+
const { mpName, mpVersion } = context.mpInfo ?? {}; //
|
|
16
17
|
const extra = {
|
|
17
18
|
...originExtra,
|
|
18
19
|
mp_id: (_data.mp_id as string) ?? '',
|
|
19
20
|
mp_version: (_data.mp_version as string) ?? '',
|
|
20
21
|
session_id: context.sessionId,
|
|
21
|
-
user_id: context.hostUserInfo?.uid ?? ''
|
|
22
|
+
user_id: context.hostUserInfo?.uid ?? '',
|
|
23
|
+
...(mpName ? { mp_name: mpName } : {}),
|
|
24
|
+
...(mpVersion ? { mp_info_version: mpVersion } : {})
|
|
22
25
|
};
|
|
23
26
|
const eventType = (_data.eventType ?? EventType.Other) as number;
|
|
24
27
|
|
|
@@ -23,12 +23,12 @@ import {
|
|
|
23
23
|
import { paymentHelper } from '@/native/payment';
|
|
24
24
|
import { createLoading } from '@jolibox/ui';
|
|
25
25
|
import { canIUseNative } from '@/native/api/base';
|
|
26
|
-
|
|
27
|
-
import { isUndefinedOrNull } from '@jolibox/common';
|
|
26
|
+
|
|
28
27
|
import { track } from '@/native/report';
|
|
29
28
|
import { updateAutoDeductConfig } from './utils';
|
|
30
29
|
import { createEventPromiseHandler } from '@/common/rewards/registers/utils/event-listener';
|
|
31
30
|
import { TrackEvent } from '@jolibox/types';
|
|
31
|
+
import { createJoliCoinPaymentService, createJoliGemPaymentService } from '@/native/payment/payment-service';
|
|
32
32
|
|
|
33
33
|
// 货币配置映射
|
|
34
34
|
interface CurrencyPaymentConfig {
|
|
@@ -85,6 +85,9 @@ const CURRENCY_PAYMENT_CONFIG: Record<'JOLI_COIN' | 'JOLI_GEM', CurrencyPaymentC
|
|
|
85
85
|
|
|
86
86
|
const loading = createLoading();
|
|
87
87
|
|
|
88
|
+
const JoliCoinPaymentService = createJoliCoinPaymentService();
|
|
89
|
+
const JoliGemPaymentService = createJoliGemPaymentService();
|
|
90
|
+
|
|
88
91
|
const modalUseFrequencyConfig = createEventPromiseHandler<
|
|
89
92
|
IUseModalFrequencyConfig,
|
|
90
93
|
typeof UseModalFrequencyEventName
|
|
@@ -114,6 +117,7 @@ rewardsEmitter.on(
|
|
|
114
117
|
await loading.show({
|
|
115
118
|
duration: 3000
|
|
116
119
|
});
|
|
120
|
+
|
|
117
121
|
const config = await modalUseFrequencyConfig.getData();
|
|
118
122
|
const { canShow: canShowPaymentModal } = await paymentConfig.frequencyChecker(
|
|
119
123
|
config.joliCoinUseAndCharge[paymentConfig.frequencyConfigKey]
|
|
@@ -134,7 +138,9 @@ rewardsEmitter.on(
|
|
|
134
138
|
await loading.show({
|
|
135
139
|
duration: 3000
|
|
136
140
|
});
|
|
137
|
-
const
|
|
141
|
+
const paymentService = currencyType === 'JOLI_COIN' ? JoliCoinPaymentService : JoliGemPaymentService;
|
|
142
|
+
// get product info from cache, if not found, get from server and cache it
|
|
143
|
+
const balenceDetails = await paymentService.getProductsInfo();
|
|
138
144
|
loading.hide();
|
|
139
145
|
|
|
140
146
|
if (!balenceDetails) {
|
|
@@ -158,7 +164,7 @@ rewardsEmitter.on(
|
|
|
158
164
|
...choice,
|
|
159
165
|
totalAmountStr: choice.totalAmountStr ?? ''
|
|
160
166
|
})) ?? [],
|
|
161
|
-
enableAutoDeduct:
|
|
167
|
+
enableAutoDeduct: params.enableAutoDeduct
|
|
162
168
|
},
|
|
163
169
|
buttons: {
|
|
164
170
|
confirm: {
|
|
@@ -183,8 +189,8 @@ rewardsEmitter.on(
|
|
|
183
189
|
return;
|
|
184
190
|
}
|
|
185
191
|
|
|
186
|
-
const
|
|
187
|
-
if ((
|
|
192
|
+
const newBalence = await paymentService.refreshProductsInfo();
|
|
193
|
+
if ((newBalence?.balance ?? 0) >= params.quantity) {
|
|
188
194
|
rewardsEmitter.emit(PaymentResultEventName, {
|
|
189
195
|
paymentResult: 'SUCCESS',
|
|
190
196
|
currency: currencyType
|
|
@@ -193,6 +199,7 @@ rewardsEmitter.on(
|
|
|
193
199
|
return;
|
|
194
200
|
}
|
|
195
201
|
}
|
|
202
|
+
// invoke native payment
|
|
196
203
|
console.log('invokeNativePayment', productId);
|
|
197
204
|
const appStoreProductId = balenceDetails?.paymentChoices?.find(
|
|
198
205
|
(choice) => choice.productId === productId
|
|
@@ -278,58 +285,11 @@ rewardsEmitter.on(
|
|
|
278
285
|
}
|
|
279
286
|
);
|
|
280
287
|
|
|
281
|
-
|
|
282
|
-
responseData: { paymentChoices: IPaymentChoice[] },
|
|
283
|
-
data: { [appStoreProductId: string]: { price: string } }
|
|
284
|
-
) => {
|
|
285
|
-
Object.keys(data).forEach((key) => {
|
|
286
|
-
const choice = responseData.paymentChoices.find((choice) => choice.appStoreProductId === key);
|
|
287
|
-
if (choice) {
|
|
288
|
-
choice.totalAmountStr = data[key].price;
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
responseData.paymentChoices = responseData.paymentChoices.filter(
|
|
293
|
-
(choice) => !isUndefinedOrNull(choice.totalAmountStr)
|
|
294
|
-
) as IPaymentChoice[];
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
const getBalenceDetails = async (
|
|
298
|
-
apiEndpoint: string
|
|
299
|
-
): Promise<
|
|
300
|
-
| {
|
|
301
|
-
balance: number;
|
|
302
|
-
enableAutoDeduct: boolean;
|
|
303
|
-
paymentChoices: IPaymentChoice[];
|
|
304
|
-
}
|
|
305
|
-
| undefined
|
|
306
|
-
> => {
|
|
307
|
-
const { response } = await fetch<
|
|
308
|
-
StandardResponse<{
|
|
309
|
-
balance: number;
|
|
310
|
-
enableAutoDeduct: boolean;
|
|
311
|
-
paymentChoices: IPaymentChoice[];
|
|
312
|
-
}>
|
|
313
|
-
>(apiEndpoint, {
|
|
314
|
-
method: 'GET',
|
|
315
|
-
appendHostCookie: true,
|
|
316
|
-
responseType: 'json'
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
console.info('getBalenceDetails', response);
|
|
320
|
-
const { data } = await applyNative('requestProductDetailsAsync', {
|
|
321
|
-
appStoreProductIds:
|
|
322
|
-
response.data?.data?.paymentChoices
|
|
323
|
-
?.filter((choice) => typeof choice.appStoreProductId === 'string')
|
|
324
|
-
.map((choice) => choice.appStoreProductId as string) ?? []
|
|
325
|
-
});
|
|
288
|
+
/** preload payment details */
|
|
326
289
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
return response.data?.data;
|
|
335
|
-
};
|
|
290
|
+
JoliCoinPaymentService.getProductsInfo().catch((e) => {
|
|
291
|
+
console.error('preload joli coin payment details failed', e);
|
|
292
|
+
});
|
|
293
|
+
JoliGemPaymentService.getProductsInfo().catch((e) => {
|
|
294
|
+
console.error('preload joli gem payment details failed', e);
|
|
295
|
+
});
|