@hayanmind/monetai-react-native 1.0.0-beta.0 → 1.0.0-beta.2
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/android/src/main/java/com/hayanmind/monetaireactnative/MonetaiReactNativeModule.kt +19 -0
- package/ios/MonetaiReactNative.mm +6 -4
- package/ios/MonetaiReactNative.swift +15 -3
- package/lib/commonjs/ApiRequest.js +42 -52
- package/lib/commonjs/ApiRequest.js.map +1 -1
- package/lib/commonjs/MonetaiSDK.js +28 -45
- package/lib/commonjs/MonetaiSDK.js.map +1 -1
- package/lib/commonjs/constants.js +14 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/lib.js +2 -2
- package/lib/module/ApiRequest.js +36 -47
- package/lib/module/ApiRequest.js.map +1 -1
- package/lib/module/MonetaiSDK.js +29 -46
- package/lib/module/MonetaiSDK.js.map +1 -1
- package/lib/module/constants.js +10 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/lib.js +2 -2
- package/lib/typescript/commonjs/src/ApiRequest.d.ts +17 -35
- package/lib/typescript/commonjs/src/ApiRequest.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/MonetaiSDK.d.ts +5 -14
- package/lib/typescript/commonjs/src/MonetaiSDK.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/constants.d.ts +8 -0
- package/lib/typescript/commonjs/src/constants.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +1 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types.d.ts +10 -3
- package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
- package/lib/typescript/module/src/ApiRequest.d.ts +17 -35
- package/lib/typescript/module/src/ApiRequest.d.ts.map +1 -1
- package/lib/typescript/module/src/MonetaiSDK.d.ts +5 -14
- package/lib/typescript/module/src/MonetaiSDK.d.ts.map +1 -1
- package/lib/typescript/module/src/constants.d.ts +8 -0
- package/lib/typescript/module/src/constants.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +1 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/types.d.ts +10 -3
- package/lib/typescript/module/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ApiRequest.ts +43 -93
- package/src/MonetaiSDK.ts +50 -70
- package/src/constants.ts +7 -0
- package/src/index.tsx +2 -3
- package/src/types.ts +11 -3
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
export type ABTestGroup = 'baseline' | 'monetai' | 'unknown';
|
|
2
2
|
export type PredictResult = 'non-purchaser' | 'purchaser' | null;
|
|
3
|
-
export interface
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export interface OfferProduct {
|
|
4
|
+
name: string;
|
|
5
|
+
sku: string;
|
|
6
|
+
discountRate: number;
|
|
7
|
+
}
|
|
8
|
+
export interface Offer {
|
|
9
|
+
agentId: number;
|
|
10
|
+
agentName: string;
|
|
11
|
+
products: OfferProduct[];
|
|
6
12
|
}
|
|
7
13
|
export type PaywallStyle = 'compact' | 'highlight-benefits' | 'key-feature-summary' | 'text-focused';
|
|
8
14
|
export interface Feature {
|
|
@@ -22,6 +28,7 @@ export interface ViewProductItemParams {
|
|
|
22
28
|
price: number;
|
|
23
29
|
regularPrice: number;
|
|
24
30
|
currencyCode: string;
|
|
31
|
+
promotionId: number;
|
|
25
32
|
month?: number | null;
|
|
26
33
|
}
|
|
27
34
|
export interface DiscountInfo {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAC7D,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,WAAW,GAAG,IAAI,CAAC;AAEjE,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/ApiRequest.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import type {
|
|
3
|
-
ABTestGroup,
|
|
4
3
|
AppUserDiscountResponse,
|
|
5
|
-
|
|
4
|
+
Offer,
|
|
5
|
+
OfferProduct,
|
|
6
6
|
ViewProductItemParams,
|
|
7
7
|
} from './types';
|
|
8
8
|
import { getSDKVersion } from './lib';
|
|
9
9
|
import { Platform } from 'react-native';
|
|
10
|
+
import { SDK_HEADERS } from './constants';
|
|
10
11
|
|
|
11
12
|
const axiosInstance = axios.create({
|
|
12
13
|
baseURL: 'https://monetai-api-414410537412.us-central1.run.app/sdk', // 필요에 따라 베이스 URL 설정
|
|
13
14
|
headers: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
[SDK_HEADERS.SDK_PLATFORM]: 'react_native',
|
|
16
|
+
[SDK_HEADERS.SDK_VERSION]: getSDKVersion(),
|
|
17
|
+
[SDK_HEADERS.DEVICE_OS]:
|
|
17
18
|
Platform.OS === 'ios'
|
|
18
19
|
? 'ios'
|
|
19
20
|
: Platform.OS === 'android'
|
|
@@ -22,6 +23,26 @@ const axiosInstance = axios.create({
|
|
|
22
23
|
},
|
|
23
24
|
});
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* X-App-Version 헤더를 설정합니다.
|
|
28
|
+
* SDK 초기화 시점에 호출되어야 합니다.
|
|
29
|
+
*/
|
|
30
|
+
export const setAppVersionHeader = (version: string) => {
|
|
31
|
+
axiosInstance.defaults.headers.common[SDK_HEADERS.APP_VERSION] = version;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* X-App-Bundle-Id 헤더를 설정합니다.
|
|
36
|
+
* SDK 초기화 시점에 호출되어야 합니다.
|
|
37
|
+
*/
|
|
38
|
+
export const setBundleIdHeader = (bundleId: string) => {
|
|
39
|
+
axiosInstance.defaults.headers.common[SDK_HEADERS.BUNDLE_ID] = bundleId;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const setUserIdHeader = (userId: string) => {
|
|
43
|
+
axiosInstance.defaults.headers.common['X-User-Id'] = userId;
|
|
44
|
+
};
|
|
45
|
+
|
|
25
46
|
export const initialize = async ({
|
|
26
47
|
sdkKey,
|
|
27
48
|
userId,
|
|
@@ -30,6 +51,9 @@ export const initialize = async ({
|
|
|
30
51
|
userId: string;
|
|
31
52
|
}) => {
|
|
32
53
|
try {
|
|
54
|
+
// X-User-Id 헤더 설정 (user property 수집용)
|
|
55
|
+
setUserIdHeader(userId);
|
|
56
|
+
|
|
33
57
|
const response = await axiosInstance.post<{
|
|
34
58
|
organization_id: number;
|
|
35
59
|
platform: 'react_native';
|
|
@@ -40,38 +64,10 @@ export const initialize = async ({
|
|
|
40
64
|
version: getSDKVersion(),
|
|
41
65
|
});
|
|
42
66
|
|
|
43
|
-
const abTestGroupResponse = await axiosInstance.post<{
|
|
44
|
-
group: ABTestGroup | null;
|
|
45
|
-
campaign: {
|
|
46
|
-
id: number;
|
|
47
|
-
created_at: Date | null;
|
|
48
|
-
organization_id: number;
|
|
49
|
-
campaign_name: string;
|
|
50
|
-
started_at: Date | null;
|
|
51
|
-
ended_at: Date | null;
|
|
52
|
-
traffic_ratio: number;
|
|
53
|
-
allocation_ratio: number;
|
|
54
|
-
discount_ratio: number;
|
|
55
|
-
exposure_time_sec: number;
|
|
56
|
-
model_accuracy: number | null;
|
|
57
|
-
} | null;
|
|
58
|
-
}>('/ab-test', {
|
|
59
|
-
sdkKey,
|
|
60
|
-
userId,
|
|
61
|
-
platform:
|
|
62
|
-
Platform.OS === 'ios'
|
|
63
|
-
? 'ios'
|
|
64
|
-
: Platform.OS === 'android'
|
|
65
|
-
? 'android'
|
|
66
|
-
: Platform.OS,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
67
|
return {
|
|
70
68
|
organizationId: response.data.organization_id,
|
|
71
69
|
platform: response.data.platform,
|
|
72
70
|
version: response.data.version,
|
|
73
|
-
group: abTestGroupResponse.data.group,
|
|
74
|
-
campaign: abTestGroupResponse.data.campaign,
|
|
75
71
|
};
|
|
76
72
|
} catch (error: any) {
|
|
77
73
|
console.error('Failed to initialize integration:', error.message);
|
|
@@ -133,6 +129,7 @@ export const createViewProductItemEvent = async ({
|
|
|
133
129
|
price: params.price,
|
|
134
130
|
regularPrice: params.regularPrice,
|
|
135
131
|
currencyCode: params.currencyCode,
|
|
132
|
+
promotionId: params.promotionId,
|
|
136
133
|
month: params.month,
|
|
137
134
|
createdAt: createdAt ?? new Date(),
|
|
138
135
|
platform:
|
|
@@ -147,55 +144,6 @@ export const createViewProductItemEvent = async ({
|
|
|
147
144
|
}
|
|
148
145
|
};
|
|
149
146
|
|
|
150
|
-
export const predict = async ({
|
|
151
|
-
userId,
|
|
152
|
-
sdkKey,
|
|
153
|
-
}: {
|
|
154
|
-
userId: string;
|
|
155
|
-
sdkKey: string;
|
|
156
|
-
}) => {
|
|
157
|
-
try {
|
|
158
|
-
const response = await axiosInstance.post<{
|
|
159
|
-
prediction: PredictResult;
|
|
160
|
-
testGroup: ABTestGroup | null;
|
|
161
|
-
}>('/predict', {
|
|
162
|
-
sdkKey,
|
|
163
|
-
userId,
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
return response.data;
|
|
167
|
-
} catch (error: any) {
|
|
168
|
-
console.error('Failed to get A/B test group:', error.message);
|
|
169
|
-
throw new Error(
|
|
170
|
-
error.response?.data?.message || 'Failed to get A/B test group'
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
export const createAppUserDiscount = async (discountInfo: {
|
|
176
|
-
startedAt: Date;
|
|
177
|
-
endedAt: Date;
|
|
178
|
-
userId: string;
|
|
179
|
-
sdkKey: string;
|
|
180
|
-
}) => {
|
|
181
|
-
try {
|
|
182
|
-
const response = await axiosInstance.post<{
|
|
183
|
-
discount: AppUserDiscountResponse;
|
|
184
|
-
}>('/app-user-discounts', {
|
|
185
|
-
sdkKey: discountInfo.sdkKey,
|
|
186
|
-
appUserId: discountInfo.userId,
|
|
187
|
-
startedAt: discountInfo.startedAt,
|
|
188
|
-
endedAt: discountInfo.endedAt,
|
|
189
|
-
});
|
|
190
|
-
return response.data.discount;
|
|
191
|
-
} catch (error: any) {
|
|
192
|
-
console.error('Failed to set discount info:', error.message);
|
|
193
|
-
throw new Error(
|
|
194
|
-
error.response?.data?.message || 'Failed to set discount info'
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
147
|
/**
|
|
200
148
|
* sdkKey와 app_user_id에 해당하는 가장 최근 할인 정보를 조회합니다.
|
|
201
149
|
* API GET /app-user-discounts/latest 엔드포인트를 호출합니다.
|
|
@@ -223,23 +171,27 @@ export const getAppUserDiscount = async ({
|
|
|
223
171
|
};
|
|
224
172
|
|
|
225
173
|
/**
|
|
226
|
-
*
|
|
227
|
-
* API POST /
|
|
174
|
+
* 오퍼 조회
|
|
175
|
+
* API POST /offers/get-offer 엔드포인트를 호출합니다.
|
|
228
176
|
*/
|
|
229
|
-
export const
|
|
177
|
+
export const getOffer = async ({
|
|
230
178
|
sdkKey,
|
|
231
179
|
userId,
|
|
180
|
+
promotionId,
|
|
232
181
|
}: {
|
|
233
182
|
sdkKey: string;
|
|
234
183
|
userId: string;
|
|
235
|
-
|
|
184
|
+
promotionId: number;
|
|
185
|
+
}): Promise<Offer | null> => {
|
|
236
186
|
try {
|
|
237
187
|
const response = await axiosInstance.post<{
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
188
|
+
agentId: number;
|
|
189
|
+
agentName: string;
|
|
190
|
+
products: OfferProduct[];
|
|
191
|
+
} | null>('/offers/get-offer', {
|
|
241
192
|
sdkKey,
|
|
242
193
|
userId,
|
|
194
|
+
promotionId,
|
|
243
195
|
platform:
|
|
244
196
|
Platform.OS === 'ios'
|
|
245
197
|
? 'ios'
|
|
@@ -249,9 +201,7 @@ export const getPriceDecision = async ({
|
|
|
249
201
|
});
|
|
250
202
|
return response.data;
|
|
251
203
|
} catch (error: any) {
|
|
252
|
-
console.error('Failed to get
|
|
253
|
-
throw new Error(
|
|
254
|
-
error.response?.data?.message || 'Failed to get price decision'
|
|
255
|
-
);
|
|
204
|
+
console.error('Failed to get offer:', error.message);
|
|
205
|
+
throw new Error(error.response?.data?.message || 'Failed to get offer');
|
|
256
206
|
}
|
|
257
207
|
};
|
package/src/MonetaiSDK.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { NativeModules, Platform } from 'react-native';
|
|
2
2
|
import mitt from 'mitt';
|
|
3
|
-
import dayjs from 'dayjs';
|
|
4
3
|
import * as ApiRequest from './ApiRequest';
|
|
5
4
|
import {
|
|
6
|
-
type
|
|
7
|
-
type PredictResult,
|
|
5
|
+
type Offer,
|
|
8
6
|
type LogEventOptions,
|
|
9
7
|
type ViewProductItemParams,
|
|
10
8
|
} from './types';
|
|
11
|
-
import {
|
|
9
|
+
import { setAppVersionHeader, setBundleIdHeader } from './ApiRequest';
|
|
12
10
|
|
|
13
11
|
const LINKING_ERROR =
|
|
14
12
|
`The package '@hayanmind/monetai-react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
@@ -16,16 +14,29 @@ const LINKING_ERROR =
|
|
|
16
14
|
'- You rebuilt the app after installing the package\n' +
|
|
17
15
|
'- You are not using Expo Go\n';
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
interface MonetaiReactNativeModule {
|
|
18
|
+
setUserId(userId: string): Promise<void>;
|
|
19
|
+
getUserId(): Promise<string | null>;
|
|
20
|
+
setSdkKey(sdkKey: string): Promise<void>;
|
|
21
|
+
getSdkKey(): Promise<string | null>;
|
|
22
|
+
startObserving(useStoreKit2: boolean): Promise<void>;
|
|
23
|
+
sendReceipt(): Promise<void>;
|
|
24
|
+
reset(): Promise<void>;
|
|
25
|
+
getAppVersion(): Promise<string | null>;
|
|
26
|
+
getBundleId(): Promise<string | null>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const MonetaiReactNative: MonetaiReactNativeModule =
|
|
30
|
+
NativeModules.MonetaiReactNative
|
|
31
|
+
? NativeModules.MonetaiReactNative
|
|
32
|
+
: new Proxy(
|
|
33
|
+
{},
|
|
34
|
+
{
|
|
35
|
+
get() {
|
|
36
|
+
throw new Error(LINKING_ERROR);
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
);
|
|
29
40
|
|
|
30
41
|
// Emitter로 사용할 이벤트 타입 정의
|
|
31
42
|
type MonetaiEvents = {
|
|
@@ -33,7 +44,6 @@ type MonetaiEvents = {
|
|
|
33
44
|
};
|
|
34
45
|
|
|
35
46
|
class MonetaiSDK {
|
|
36
|
-
private exposureTimeSec: number | null = null;
|
|
37
47
|
private initialized = false;
|
|
38
48
|
|
|
39
49
|
// SDK 초기화 전에 로깅된 이벤트들을 저장할 큐
|
|
@@ -51,10 +61,6 @@ class MonetaiSDK {
|
|
|
51
61
|
return this.emitter;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
|
-
public getExposureTimeSec() {
|
|
55
|
-
return this.exposureTimeSec;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
64
|
/**
|
|
59
65
|
* 모넷AI SDK를 초기화합니다
|
|
60
66
|
* @param userId 사용자 고유 ID (필수)
|
|
@@ -76,7 +82,6 @@ class MonetaiSDK {
|
|
|
76
82
|
platform: 'react_native';
|
|
77
83
|
version: string;
|
|
78
84
|
userId: string;
|
|
79
|
-
group: ABTestGroup | null;
|
|
80
85
|
}> {
|
|
81
86
|
if (!userId) {
|
|
82
87
|
throw new Error('userId is required');
|
|
@@ -91,6 +96,26 @@ class MonetaiSDK {
|
|
|
91
96
|
// userId 설정
|
|
92
97
|
await MonetaiReactNative.setUserId(userId);
|
|
93
98
|
|
|
99
|
+
// 앱 버전을 가져와서 API 헤더에 설정
|
|
100
|
+
try {
|
|
101
|
+
const appVersion = await MonetaiReactNative.getAppVersion();
|
|
102
|
+
if (appVersion) {
|
|
103
|
+
setAppVersionHeader(appVersion);
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.warn('[MonetaiSDK] Failed to get app version:', error);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Bundle ID / Package Name을 가져와서 API 헤더에 설정
|
|
110
|
+
try {
|
|
111
|
+
const bundleId = await MonetaiReactNative.getBundleId();
|
|
112
|
+
if (bundleId) {
|
|
113
|
+
setBundleIdHeader(bundleId);
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.warn('[MonetaiSDK] Failed to get bundle id:', error);
|
|
117
|
+
}
|
|
118
|
+
|
|
94
119
|
// 트랜잭션 관찰 시작
|
|
95
120
|
await MonetaiReactNative.startObserving(useStoreKit2);
|
|
96
121
|
|
|
@@ -100,7 +125,6 @@ class MonetaiSDK {
|
|
|
100
125
|
});
|
|
101
126
|
|
|
102
127
|
const result = await ApiRequest.initialize({ sdkKey, userId });
|
|
103
|
-
this.exposureTimeSec = result.campaign?.exposure_time_sec ?? null;
|
|
104
128
|
this.initialized = true;
|
|
105
129
|
|
|
106
130
|
// SDK 초기화 후, 초기화 전에 저장된 pendingEvents를 전송
|
|
@@ -128,7 +152,6 @@ class MonetaiSDK {
|
|
|
128
152
|
platform: 'react_native',
|
|
129
153
|
version: result.version,
|
|
130
154
|
userId: userId,
|
|
131
|
-
group: result.group,
|
|
132
155
|
};
|
|
133
156
|
}
|
|
134
157
|
|
|
@@ -186,55 +209,12 @@ class MonetaiSDK {
|
|
|
186
209
|
});
|
|
187
210
|
}
|
|
188
211
|
|
|
189
|
-
// Non-Purchaser 예측
|
|
190
|
-
public async predict(): Promise<{
|
|
191
|
-
prediction: PredictResult;
|
|
192
|
-
testGroup: ABTestGroup | null;
|
|
193
|
-
}> {
|
|
194
|
-
const sdkKey = await this.getSdkKey();
|
|
195
|
-
const userId = await this.getUserId();
|
|
196
|
-
|
|
197
|
-
if (!sdkKey || !userId || !this.exposureTimeSec) {
|
|
198
|
-
throw new Error(
|
|
199
|
-
'MonetaiSDK is not initialized. Call initialize() first.'
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
const result = await ApiRequest.predict({ userId, sdkKey });
|
|
203
|
-
|
|
204
|
-
if (result.prediction === 'non-purchaser') {
|
|
205
|
-
const discountInfo = await ApiRequest.getAppUserDiscount({
|
|
206
|
-
sdkKey,
|
|
207
|
-
userId,
|
|
208
|
-
});
|
|
209
|
-
const hasActiveDiscount =
|
|
210
|
-
discountInfo != null &&
|
|
211
|
-
discountInfo.app_user_id === userId &&
|
|
212
|
-
dayjs(discountInfo.ended_at).isAfter(dayjs());
|
|
213
|
-
|
|
214
|
-
if (!hasActiveDiscount) {
|
|
215
|
-
const startedAt = dayjs();
|
|
216
|
-
const endedAt = startedAt.clone().add(this.exposureTimeSec, 'second');
|
|
217
|
-
await createAppUserDiscount({
|
|
218
|
-
startedAt: startedAt.toDate(),
|
|
219
|
-
endedAt: endedAt.toDate(),
|
|
220
|
-
userId,
|
|
221
|
-
sdkKey,
|
|
222
|
-
});
|
|
223
|
-
this.emitter.emit('LOAD_DISCOUNT_INFO');
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return result;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
212
|
/**
|
|
231
|
-
*
|
|
232
|
-
* @
|
|
213
|
+
* 오퍼 조회
|
|
214
|
+
* @param promotionId 프로모션 ID
|
|
215
|
+
* @returns 에이전트 매칭 결과 및 상품 목록, 없으면 null
|
|
233
216
|
*/
|
|
234
|
-
public async
|
|
235
|
-
productId: string;
|
|
236
|
-
discount: number;
|
|
237
|
-
}> {
|
|
217
|
+
public async getOffer(promotionId: number): Promise<Offer | null> {
|
|
238
218
|
const sdkKey = await this.getSdkKey();
|
|
239
219
|
const userId = await this.getUserId();
|
|
240
220
|
|
|
@@ -244,7 +224,7 @@ class MonetaiSDK {
|
|
|
244
224
|
);
|
|
245
225
|
}
|
|
246
226
|
|
|
247
|
-
return await ApiRequest.
|
|
227
|
+
return await ApiRequest.getOffer({ sdkKey, userId, promotionId });
|
|
248
228
|
}
|
|
249
229
|
|
|
250
230
|
public getInitialized() {
|
package/src/constants.ts
ADDED
package/src/index.tsx
CHANGED
|
@@ -26,8 +26,6 @@ export {
|
|
|
26
26
|
|
|
27
27
|
// Export types
|
|
28
28
|
export type {
|
|
29
|
-
ABTestGroup,
|
|
30
|
-
PredictResult,
|
|
31
29
|
EventParams,
|
|
32
30
|
LogEventOptions,
|
|
33
31
|
DiscountInfo,
|
|
@@ -37,5 +35,6 @@ export type {
|
|
|
37
35
|
BannerParams,
|
|
38
36
|
PaywallParams,
|
|
39
37
|
PaywallStyle,
|
|
40
|
-
|
|
38
|
+
Offer,
|
|
39
|
+
OfferProduct,
|
|
41
40
|
} from './types';
|
package/src/types.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
export type ABTestGroup = 'baseline' | 'monetai' | 'unknown';
|
|
2
2
|
export type PredictResult = 'non-purchaser' | 'purchaser' | null;
|
|
3
3
|
|
|
4
|
-
export interface
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export interface OfferProduct {
|
|
5
|
+
name: string;
|
|
6
|
+
sku: string;
|
|
7
|
+
discountRate: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Offer {
|
|
11
|
+
agentId: number;
|
|
12
|
+
agentName: string;
|
|
13
|
+
products: OfferProduct[];
|
|
7
14
|
}
|
|
8
15
|
|
|
9
16
|
// Banner and Paywall style types
|
|
@@ -34,6 +41,7 @@ export interface ViewProductItemParams {
|
|
|
34
41
|
price: number;
|
|
35
42
|
regularPrice: number;
|
|
36
43
|
currencyCode: string;
|
|
44
|
+
promotionId: number;
|
|
37
45
|
month?: number | null;
|
|
38
46
|
}
|
|
39
47
|
|