@jolibox/implement 1.1.37 → 1.1.39

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.
Files changed (48) hide show
  1. package/.rush/temp/package-deps_build.json +26 -15
  2. package/dist/common/rewards/registers/utils/coins/commands/index.d.ts +3 -0
  3. package/dist/common/rewards/registers/utils/coins/commands/use-jolicoin.d.ts +16 -0
  4. package/dist/common/rewards/registers/utils/coins/commands/use-payment.d.ts +16 -0
  5. package/dist/common/rewards/registers/utils/coins/commands/use-unlogin.d.ts +18 -0
  6. package/dist/common/rewards/registers/utils/coins/fetch-balance.d.ts +4 -0
  7. package/dist/common/rewards/registers/utils/coins/index.d.ts +3 -17
  8. package/dist/common/rewards/registers/utils/coins/rewards-command.d.ts +1 -0
  9. package/dist/common/rewards/registers/utils/common.d.ts +8 -0
  10. package/dist/common/rewards/registers/utils/event-listener.d.ts +1 -0
  11. package/dist/common/rewards/reward-emitter.d.ts +30 -4
  12. package/dist/common/utils/index.d.ts +19 -0
  13. package/dist/index.js +25 -25
  14. package/dist/index.native.js +132 -46
  15. package/dist/native/api/login.d.ts +20 -0
  16. package/dist/native/rewards/check-frequency.d.ts +13 -16
  17. package/dist/native/rewards/index.d.ts +3 -1
  18. package/dist/native/rewards/ui/payment-modal.d.ts +1 -0
  19. package/dist/native/rewards/ui/unlogin-modal.d.ts +1 -0
  20. package/dist/native/rewards/ui/use-modal.d.ts +1 -0
  21. package/dist/native/rewards/ui/utils.d.ts +6 -0
  22. package/implement.build.log +2 -2
  23. package/package.json +5 -5
  24. package/src/common/rewards/fetch-reward.ts +6 -3
  25. package/src/common/rewards/registers/use-jolicoin-only.ts +13 -13
  26. package/src/common/rewards/registers/use-jolicoin.ts +15 -11
  27. package/src/common/rewards/registers/utils/coins/commands/index.ts +3 -0
  28. package/src/common/rewards/registers/utils/coins/commands/use-jolicoin.ts +67 -0
  29. package/src/common/rewards/registers/utils/coins/commands/use-payment.ts +85 -0
  30. package/src/common/rewards/registers/utils/coins/commands/use-unlogin.ts +96 -0
  31. package/src/common/rewards/registers/utils/coins/fetch-balance.ts +15 -0
  32. package/src/common/rewards/registers/utils/coins/index.ts +45 -99
  33. package/src/common/rewards/registers/utils/coins/rewards-command.ts +3 -0
  34. package/src/common/rewards/registers/utils/common.ts +8 -0
  35. package/src/common/rewards/registers/utils/event-listener.ts +13 -0
  36. package/src/common/rewards/reward-emitter.ts +33 -4
  37. package/src/common/rewards/reward-helper.ts +3 -3
  38. package/src/common/utils/index.ts +20 -0
  39. package/src/h5/bootstrap/index.ts +20 -2
  40. package/src/h5/rewards/index.ts +29 -1
  41. package/src/native/api/ads.ts +17 -7
  42. package/src/native/api/login.ts +62 -32
  43. package/src/native/rewards/check-frequency.ts +46 -84
  44. package/src/native/rewards/index.ts +3 -370
  45. package/src/native/rewards/ui/payment-modal.ts +254 -0
  46. package/src/native/rewards/ui/unlogin-modal.ts +121 -0
  47. package/src/native/rewards/ui/use-modal.ts +104 -0
  48. package/src/native/rewards/ui/utils.ts +25 -0
@@ -0,0 +1,254 @@
1
+ import {
2
+ rewardsEmitter,
3
+ PaymentResultEventName,
4
+ InvokePaymentEventName,
5
+ IInvokePaymentEvent,
6
+ IPaymentChoice,
7
+ UseModalFrequencyEventName,
8
+ IUseModalFrequencyConfig
9
+ } from '@/common/rewards/reward-emitter';
10
+ import { createPaymentJolicoinModal } from '@jolibox/ui';
11
+ import { innerFetch as fetch } from '@/native/network';
12
+ import { StandardResponse } from '@jolibox/types';
13
+ import { context } from '@/common/context';
14
+ import { login } from '@/native/api/login';
15
+ import { EventType } from '@jolibox/common';
16
+
17
+ import { checkPaymentFrequency, updatePaymentFrequency } from '../check-frequency';
18
+ import { paymentHelper } from '@/native/payment';
19
+ import { createLoading } from '@jolibox/ui';
20
+ import { canIUseNative } from '@/native/api/base';
21
+ import { applyNative } from '@jolibox/native-bridge';
22
+ import { isUndefinedOrNull } from '@jolibox/common';
23
+ import { track } from '@/native/report';
24
+ import { updateAutoDeductConfig } from './utils';
25
+ import { createEventPromiseHandler } from '@/common/rewards/registers/utils/event-listener';
26
+
27
+ const loading = createLoading();
28
+
29
+ const modalUseFrequencyConfig = createEventPromiseHandler<
30
+ IUseModalFrequencyConfig,
31
+ typeof UseModalFrequencyEventName
32
+ >(rewardsEmitter, UseModalFrequencyEventName);
33
+ /**
34
+ * payment jolicoin modal
35
+ */
36
+ rewardsEmitter.on(
37
+ InvokePaymentEventName,
38
+ async (type: 'JOLI_COIN' | 'ADS-JOLI_COIN', params: IInvokePaymentEvent) => {
39
+ try {
40
+ // TODO: temp remove it for dev
41
+ if (!canIUseNative('requestPaymentSync:paymentBody:appStoreProductId')) {
42
+ //TODO: show Toast
43
+ console.info('requestPaymentSync:paymentBody:appStoreProductId not supported');
44
+ setTimeout(() => {
45
+ rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'FAILED' });
46
+ }, 0);
47
+ return;
48
+ }
49
+
50
+ // handle showup frequecy
51
+ if (type === 'ADS-JOLI_COIN') {
52
+ await loading.show({
53
+ duration: 3000
54
+ });
55
+ const config = await modalUseFrequencyConfig.getData();
56
+ const { canShow: canShowPaymentModal } = await checkPaymentFrequency(
57
+ config.joliCoinUseAndCharge.charge
58
+ );
59
+ console.log('use payment show by frequency', canShowPaymentModal);
60
+ loading.hide();
61
+ if (!canShowPaymentModal) {
62
+ // return by frequency control
63
+ rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'FAILED' });
64
+ return;
65
+ }
66
+ console.log('show by frequency');
67
+ }
68
+
69
+ /**
70
+ * TODO: need merge totalAmountStr from native
71
+ */
72
+ await loading.show({
73
+ duration: 3000
74
+ });
75
+ const balenceDetails = await getBalenceDetails();
76
+ loading.hide();
77
+
78
+ if (!balenceDetails) {
79
+ rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'FAILED' });
80
+ return;
81
+ }
82
+
83
+ track('coinorder_show', {
84
+ targetType: 'game',
85
+ eventType: EventType.View
86
+ });
87
+
88
+ const modal = createPaymentJolicoinModal({
89
+ data: {
90
+ userJolicoin: params.userJoliCoin,
91
+ joliCoinQuantity: params.joliCoinQuantity,
92
+ paymentChoices:
93
+ balenceDetails.paymentChoices?.map((choice) => ({
94
+ ...choice,
95
+ totalAmountStr: choice.totalAmountStr ?? ''
96
+ })) ?? [],
97
+ enableAutoDeduct: balenceDetails.enableAutoDeduct
98
+ },
99
+ buttons: {
100
+ confirm: {
101
+ text: params.confirmButtonText,
102
+ onPress: async (productId: string) => {
103
+ track('order_pay_ensure', {
104
+ targetType: 'game',
105
+ eventType: EventType.Click,
106
+ payWay: 'app_iap',
107
+ coinAmount: params.joliCoinQuantity,
108
+ orderPrice:
109
+ balenceDetails.paymentChoices.find((choice) => choice.productId === productId)
110
+ ?.totalAmountStr ?? ''
111
+ });
112
+ if (!context.hostUserInfo?.isLogin) {
113
+ const { data } = await login({
114
+ skipLogin: true
115
+ });
116
+ if (!data?.isLogin) {
117
+ console.log('login failed');
118
+ return;
119
+ }
120
+
121
+ const balenceDetails = await getBalenceDetails();
122
+ if ((balenceDetails?.balance ?? 0) >= params.joliCoinQuantity) {
123
+ rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'SUCCESS' });
124
+ modal.destroy();
125
+ return;
126
+ }
127
+ }
128
+ console.log('invokeNativePayment', productId);
129
+ const appStoreProductId = balenceDetails?.paymentChoices?.find(
130
+ (choice) => choice.productId === productId
131
+ )?.appStoreProductId;
132
+
133
+ if (!appStoreProductId) {
134
+ rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'FAILED' });
135
+ modal.destroy();
136
+ return;
137
+ }
138
+ await loading.show({
139
+ duration: 3000
140
+ });
141
+ const { code } = await paymentHelper.invokePayment('JOLI_COIN_IAP', {
142
+ productId,
143
+ appStoreProductId
144
+ });
145
+ loading.hide();
146
+ track('order_pay_result', {
147
+ eventType: EventType.Other,
148
+ targetType: 'game',
149
+ payWay: 'app_iap',
150
+ coinAmount: params.joliCoinQuantity,
151
+ orderPrice:
152
+ balenceDetails.paymentChoices.find((choice) => choice.productId === productId)
153
+ ?.totalAmountStr ?? '',
154
+ payResult: code
155
+ });
156
+ if (code !== 'SUCCESS') {
157
+ /** add timeout for google panel closed */
158
+ console.info('[JoliboxSDK] payment failed in payment.invokePaymet');
159
+ return;
160
+ }
161
+ rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'SUCCESS' });
162
+ modal.destroy();
163
+ }
164
+ },
165
+ cancel: {
166
+ text: params.cancelButtonText,
167
+ onPress: ({ type }) => {
168
+ rewardsEmitter.emit(PaymentResultEventName, {
169
+ paymentResult: (type ?? '') === 'CANCEL' ? 'CANCEL' : 'FAILED'
170
+ });
171
+ track('ad_unlock_click', {
172
+ targetType: 'game',
173
+ eventType: EventType.Click
174
+ });
175
+ modal.destroy();
176
+ }
177
+ },
178
+ onEnableDeductChanged: async (enabled: boolean) => {
179
+ await updateAutoDeductConfig(enabled);
180
+ }
181
+ },
182
+ onSelect: (productId: string) => {
183
+ track('coinorder_click', {
184
+ targetType: 'game',
185
+ eventType: EventType.Click,
186
+ coinAmount: params.joliCoinQuantity,
187
+ orderPrice:
188
+ balenceDetails.paymentChoices.find((choice) => choice.productId === productId)
189
+ ?.totalAmountStr ?? ''
190
+ });
191
+ }
192
+ });
193
+
194
+ await updatePaymentFrequency();
195
+ } catch (error) {
196
+ console.info('payment failed', error);
197
+ rewardsEmitter.emit(PaymentResultEventName, { paymentResult: 'FAILED' });
198
+ }
199
+ }
200
+ );
201
+
202
+ const mergeResponseData = (
203
+ responseData: { paymentChoices: IPaymentChoice[] },
204
+ data: { [appStoreProductId: string]: { price: string } }
205
+ ) => {
206
+ Object.keys(data).forEach((key) => {
207
+ const choice = responseData.paymentChoices.find((choice) => choice.appStoreProductId === key);
208
+ if (choice) {
209
+ choice.totalAmountStr = data[key].price;
210
+ }
211
+ });
212
+
213
+ responseData.paymentChoices = responseData.paymentChoices.filter(
214
+ (choice) => !isUndefinedOrNull(choice.totalAmountStr)
215
+ ) as IPaymentChoice[];
216
+ };
217
+
218
+ const getBalenceDetails = async (): Promise<
219
+ | {
220
+ balance: number;
221
+ enableAutoDeduct: boolean;
222
+ paymentChoices: IPaymentChoice[];
223
+ }
224
+ | undefined
225
+ > => {
226
+ const { response } = await fetch<
227
+ StandardResponse<{
228
+ balance: number;
229
+ enableAutoDeduct: boolean;
230
+ paymentChoices: IPaymentChoice[];
231
+ }>
232
+ >('/api/joli-coin/balance-detail', {
233
+ method: 'GET',
234
+ appendHostCookie: true,
235
+ responseType: 'json'
236
+ });
237
+
238
+ console.info('getBalenceDetails', response);
239
+ const { data } = await applyNative('requestProductDetailsAsync', {
240
+ appStoreProductIds:
241
+ response.data?.data?.paymentChoices
242
+ ?.filter((choice) => typeof choice.appStoreProductId === 'string')
243
+ .map((choice) => choice.appStoreProductId as string) ?? []
244
+ });
245
+
246
+ if (response.data?.data && data) {
247
+ mergeResponseData(response.data?.data, data);
248
+ }
249
+ console.info('productDetails', response.data?.data);
250
+ if (response.data?.data?.paymentChoices.length === 0) {
251
+ throw new Error('paymentChoices is empty');
252
+ }
253
+ return response.data?.data;
254
+ };
@@ -0,0 +1,121 @@
1
+ import {
2
+ InvokeUnloginModalEventName,
3
+ IUseModalFrequencyConfig,
4
+ rewardsEmitter,
5
+ UseModalFrequencyEventName,
6
+ UseUnloginModalResultEventName
7
+ } from '@/common/rewards/reward-emitter';
8
+ import { createEventPromiseHandler } from '@/common/rewards/registers/utils/event-listener';
9
+ import { checkUnloginModalFrequency, updateUnloginModalFrequency } from '../check-frequency';
10
+ import { StandardResponse } from '@jolibox/types';
11
+ import { innerFetch as fetch } from '@/native/network';
12
+ import { reportError } from '@/common/report/errors/report';
13
+ import { InternalInvokeMethodError } from '@jolibox/common';
14
+ import { loginImplement } from '@/native/api/login';
15
+ import { createToast, createUnloginJolicoinModal } from '@jolibox/ui';
16
+
17
+ const unloginModalConfig = createEventPromiseHandler<
18
+ IUseModalFrequencyConfig,
19
+ typeof UseModalFrequencyEventName
20
+ >(rewardsEmitter, UseModalFrequencyEventName);
21
+
22
+ unloginModalConfig.getData();
23
+
24
+ rewardsEmitter.on(InvokeUnloginModalEventName, async (type: 'JOLI_COIN' | 'ADS-JOLI_COIN', params) => {
25
+ try {
26
+ if (type === 'ADS-JOLI_COIN') {
27
+ const config = await unloginModalConfig.getData();
28
+ console.log('unlogin guide config', config.loginGuide);
29
+
30
+ if (!config.loginGuide.show) {
31
+ rewardsEmitter.emit(UseUnloginModalResultEventName, { result: 'NOT_SUPPORT' });
32
+ return;
33
+ }
34
+ const { canShow: canShowUseModal } = await checkUnloginModalFrequency(config.loginGuide);
35
+
36
+ console.log('canShowUseModal', canShowUseModal);
37
+ if (!canShowUseModal) {
38
+ rewardsEmitter.emit(UseUnloginModalResultEventName, { result: 'FAILED' });
39
+ return;
40
+ }
41
+ }
42
+
43
+ const { firstLogin } = (await getRewardCoin()) ?? {};
44
+ if (!firstLogin?.reward) {
45
+ console.log('[JoliboxSDK] unlogin modal reward is empty');
46
+ rewardsEmitter.emit(UseUnloginModalResultEventName, { result: 'NOT_SUPPORT' });
47
+ return;
48
+ }
49
+ const modal = createUnloginJolicoinModal({
50
+ data: {
51
+ rewardType: type,
52
+ rewardValue: firstLogin.reward.rewardValue
53
+ },
54
+ buttons: {
55
+ confirm: {
56
+ text: params.confirmButtonText,
57
+ onPress: async () => {
58
+ const { isLogin, extra, isFirstLogin } = await loginImplement({}, true);
59
+ if (!isLogin) {
60
+ console.log('login failed');
61
+ return;
62
+ }
63
+ if (isFirstLogin && extra?.firstLogin?.reward) {
64
+ const { rewardValue } = extra.firstLogin.reward;
65
+ createToast(`{slot-i18ntran-loginGuide.rewardTips}`, {
66
+ i18nParams: {
67
+ text: 'Jolicoin Used',
68
+ coin: rewardValue
69
+ },
70
+ position: 'top',
71
+ duration: 3000
72
+ });
73
+ }
74
+
75
+ rewardsEmitter.emit(UseUnloginModalResultEventName, {
76
+ result: 'SUCCESS',
77
+ rewards: {
78
+ jolicoin: {
79
+ claimedRewardValue: extra?.firstLogin?.reward?.rewardValue ?? 0,
80
+ isFirstLogin: isFirstLogin ?? false
81
+ }
82
+ }
83
+ });
84
+ modal.destroy();
85
+ return;
86
+ }
87
+ },
88
+ cancel: {
89
+ text: params.cancelButtonText,
90
+ onPress: () => {
91
+ rewardsEmitter.emit(UseUnloginModalResultEventName, { result: 'FAILED' });
92
+ modal.destroy();
93
+ }
94
+ }
95
+ }
96
+ });
97
+ await updateUnloginModalFrequency();
98
+ } catch (e) {
99
+ reportError(new InternalInvokeMethodError(e as Error));
100
+ rewardsEmitter.emit(UseUnloginModalResultEventName, { result: 'FAILED' });
101
+ }
102
+ });
103
+
104
+ interface IRewardCoinResponse {
105
+ firstLogin: {
106
+ reward: {
107
+ rewardType: 'JOLI_COIN';
108
+ rewardValue: number;
109
+ };
110
+ };
111
+ }
112
+
113
+ const getRewardCoin = async (): Promise<IRewardCoinResponse | undefined> => {
114
+ const { response } = await fetch<StandardResponse<IRewardCoinResponse>>('/api/base/global-config', {
115
+ method: 'GET',
116
+ appendHostCookie: true,
117
+ responseType: 'json'
118
+ });
119
+
120
+ return response.data?.data;
121
+ };
@@ -0,0 +1,104 @@
1
+ import { checkUseModalFrequency, updateUseModalFrequency } from '../check-frequency';
2
+ import { updateAutoDeductConfig } from './utils';
3
+ import {
4
+ IUseModalFrequencyConfig,
5
+ rewardsEmitter,
6
+ UseModalFrequencyEventName,
7
+ IUseModalEvent
8
+ } from '@/common/rewards/reward-emitter';
9
+ import { UseModalEventName, UseModalResultEventName } from '@/common/rewards/reward-emitter';
10
+ import { createConfirmJolicoinModal, createLoading } from '@jolibox/ui';
11
+ import { track } from '@/native/report';
12
+ import { EventType } from '@jolibox/common';
13
+ import {} from '@jolibox/ui';
14
+ import { createEventPromiseHandler } from '@/common/rewards/registers/utils/event-listener';
15
+
16
+ const loading = createLoading();
17
+
18
+ const modalUseFrequencyConfig = createEventPromiseHandler<
19
+ IUseModalFrequencyConfig,
20
+ typeof UseModalFrequencyEventName
21
+ >(rewardsEmitter, UseModalFrequencyEventName);
22
+
23
+ modalUseFrequencyConfig.getData();
24
+ /**
25
+ * confirm jolicoin modal
26
+ */
27
+ rewardsEmitter.on(UseModalEventName, async (type: 'JOLI_COIN' | 'ADS-JOLI_COIN', params: IUseModalEvent) => {
28
+ if (type === 'ADS-JOLI_COIN') {
29
+ //TODO
30
+ await loading.show({
31
+ duration: 3000
32
+ });
33
+ const config = await modalUseFrequencyConfig.getData();
34
+ const { canShow: canShowUseModal, isFirst: isFirstUseModal } = await checkUseModalFrequency(
35
+ config.joliCoinUseAndCharge.useJolicoin
36
+ );
37
+ console.log('use modal show by frequency', canShowUseModal, isFirstUseModal);
38
+ loading.hide();
39
+
40
+ // First, check for direct use: sufficient balance, auto-deduct enabled, and not the first modal.
41
+ const { balance } = params.userJoliCoin;
42
+ const useDirectly = balance >= params.joliCoinQuantity && params.enableAutoDeduct;
43
+
44
+ if (useDirectly && !isFirstUseModal) {
45
+ rewardsEmitter.emit(UseModalResultEventName, { useModalResult: 'CONFIRM' });
46
+ return;
47
+ }
48
+
49
+ // If not used directly, then check frequency control.
50
+ if (!canShowUseModal) {
51
+ // confirm by frequency control
52
+ rewardsEmitter.emit(UseModalResultEventName, { useModalResult: 'FAILED' });
53
+ return;
54
+ }
55
+ }
56
+
57
+ track('unlock_popup_show', {
58
+ eventType: EventType.View,
59
+ targetType: 'game'
60
+ });
61
+
62
+ const modal = createConfirmJolicoinModal({
63
+ data: {
64
+ enableAutoDeduct: params.enableAutoDeduct,
65
+ userJolicoin: params.userJoliCoin,
66
+ joliCoinQuantity: params.joliCoinQuantity
67
+ },
68
+ buttons: {
69
+ confirm: {
70
+ text: params.confirmButtonText,
71
+ onPress: () => {
72
+ track('coin_unlock_click', {
73
+ targetType: 'game',
74
+ eventType: EventType.Click,
75
+ coinConsume: params.joliCoinQuantity,
76
+ ifAutoUnlock: params.enableAutoDeduct
77
+ });
78
+ rewardsEmitter.emit(UseModalResultEventName, { useModalResult: 'CONFIRM' });
79
+ modal.destroy();
80
+ }
81
+ },
82
+ cancel: {
83
+ text: params.cancelButtonText,
84
+ onPress: ({ type }) => {
85
+ if (type === 'FAILED') {
86
+ track('ad_unlock_click', {
87
+ targetType: 'game',
88
+ eventType: EventType.Click
89
+ });
90
+ }
91
+ rewardsEmitter.emit(UseModalResultEventName, {
92
+ useModalResult: (type ?? '') === 'CANCEL' ? 'CANCEL' : 'FAILED'
93
+ });
94
+ modal.destroy();
95
+ }
96
+ },
97
+ onEnableDeductChanged: async (enabled: boolean) => {
98
+ await updateAutoDeductConfig(enabled);
99
+ }
100
+ }
101
+ });
102
+
103
+ await updateUseModalFrequency();
104
+ });
@@ -0,0 +1,25 @@
1
+ import { innerFetch as fetch } from '@/native/network';
2
+ /**
3
+ * update config
4
+ */
5
+
6
+ let updateEnableConfigPromise = Promise.resolve();
7
+
8
+ /**
9
+ * 更新自动扣费配置的函数
10
+ * @param enabled 是否启用自动扣费
11
+ * @returns Promise 更新操作的Promise
12
+ */
13
+ export const updateAutoDeductConfig = async (enabled: boolean): Promise<void> => {
14
+ updateEnableConfigPromise = updateEnableConfigPromise.then(async () => {
15
+ await fetch('/api/joli-coin/user-config', {
16
+ method: 'POST',
17
+ appendHostCookie: true,
18
+ data: {
19
+ enableAutoDeduct: enabled
20
+ }
21
+ });
22
+ });
23
+
24
+ await updateEnableConfigPromise;
25
+ };