@blux.ai/web-sdk 1.3.0 → 2.1.0
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/README.md +46 -31
- package/dist/package.json +1 -1
- package/dist/src/BluxClient.d.ts +32 -15
- package/dist/src/BluxClient.js +195 -53
- package/dist/src/BluxClient.js.map +1 -1
- package/dist/src/apis/APIs.d.ts +180 -92
- package/dist/src/apis/APIs.js +45 -2
- package/dist/src/apis/APIs.js.map +1 -1
- package/dist/src/apis/createCrmEvent.d.ts +4 -0
- package/dist/src/apis/createCrmEvent.js +7 -0
- package/dist/src/apis/createCrmEvent.js.map +1 -0
- package/dist/src/apis/createEvent.d.ts +1 -1
- package/dist/src/apis/createEvent.js.map +1 -1
- package/dist/src/apis/getItemRecommendations.d.ts +1 -1
- package/dist/src/apis/getItemRecommendations.js.map +1 -1
- package/dist/src/apis/inappsDispatch.d.ts +5 -0
- package/dist/src/apis/inappsDispatch.js +7 -0
- package/dist/src/apis/inappsDispatch.js.map +1 -0
- package/dist/src/apis/initialize.d.ts +1 -1
- package/dist/src/apis/initialize.js.map +1 -1
- package/dist/src/apis/signIn.d.ts +1 -1
- package/dist/src/apis/signIn.js.map +1 -1
- package/dist/src/apis/signOut.d.ts +1 -1
- package/dist/src/apis/signOut.js.map +1 -1
- package/dist/src/apis/updateCustomUserProperties.d.ts +1 -1
- package/dist/src/apis/updateCustomUserProperties.js.map +1 -1
- package/dist/src/apis/updateUserProperties.d.ts +1 -1
- package/dist/src/apis/updateUserProperties.js.map +1 -1
- package/dist/src/events/AddCartaddEvent.d.ts +2 -2
- package/dist/src/events/AddCartaddEvent.js +3 -3
- package/dist/src/events/AddCartaddEvent.js.map +1 -1
- package/dist/src/events/AddClickEvent.d.ts +2 -2
- package/dist/src/events/AddClickEvent.js +3 -3
- package/dist/src/events/AddClickEvent.js.map +1 -1
- package/dist/src/events/AddCustomEvent.d.ts +2 -2
- package/dist/src/events/AddCustomEvent.js +4 -4
- package/dist/src/events/AddCustomEvent.js.map +1 -1
- package/dist/src/events/AddInstantImpressionEvent.d.ts +2 -2
- package/dist/src/events/AddInstantImpressionEvent.js +3 -3
- package/dist/src/events/AddInstantImpressionEvent.js.map +1 -1
- package/dist/src/events/AddLikeEvent.d.ts +2 -2
- package/dist/src/events/AddLikeEvent.js +3 -3
- package/dist/src/events/AddLikeEvent.js.map +1 -1
- package/dist/src/events/AddOrderEvent.d.ts +5 -0
- package/dist/src/events/AddOrderEvent.js +16 -0
- package/dist/src/events/AddOrderEvent.js.map +1 -0
- package/dist/src/events/AddPageViewEvent.d.ts +2 -2
- package/dist/src/events/AddPageViewEvent.js +2 -2
- package/dist/src/events/AddPageViewEvent.js.map +1 -1
- package/dist/src/events/AddPageVisitEvent.d.ts +2 -2
- package/dist/src/events/AddPageVisitEvent.js +2 -2
- package/dist/src/events/AddPageVisitEvent.js.map +1 -1
- package/dist/src/events/AddPersistentImpressionEvent.d.ts +2 -2
- package/dist/src/events/AddPersistentImpressionEvent.js +3 -3
- package/dist/src/events/AddPersistentImpressionEvent.js.map +1 -1
- package/dist/src/events/AddProductDetailViewEvent.d.ts +2 -2
- package/dist/src/events/AddProductDetailViewEvent.js +3 -3
- package/dist/src/events/AddProductDetailViewEvent.js.map +1 -1
- package/dist/src/events/AddRateEvent.d.ts +2 -2
- package/dist/src/events/AddRateEvent.js +3 -3
- package/dist/src/events/AddRateEvent.js.map +1 -1
- package/dist/src/events/AddSearchEvent.d.ts +2 -2
- package/dist/src/events/AddSearchEvent.js +3 -3
- package/dist/src/events/AddSearchEvent.js.map +1 -1
- package/dist/src/events/AddSectionViewEvent.d.ts +2 -2
- package/dist/src/events/AddSectionViewEvent.js +2 -2
- package/dist/src/events/AddSectionViewEvent.js.map +1 -1
- package/dist/src/events/Event.d.ts +1 -0
- package/dist/src/events/Event.js +1 -0
- package/dist/src/events/Event.js.map +1 -1
- package/dist/src/events/VisitEvent.d.ts +2 -2
- package/dist/src/events/VisitEvent.js +2 -2
- package/dist/src/events/VisitEvent.js.map +1 -1
- package/dist/src/events/index.d.ts +1 -1
- package/dist/src/events/index.js +1 -1
- package/dist/src/events/index.js.map +1 -1
- package/dist/src/events/types.d.ts +26 -15
- package/dist/src/events/types.js.map +1 -1
- package/dist/src/recs/ItemRec.js.map +1 -1
- package/dist/src/utils/LocalStorage.d.ts +2 -0
- package/dist/src/utils/LocalStorage.js +8 -1
- package/dist/src/utils/LocalStorage.js.map +1 -1
- package/dist/src/utils/Logger.js +0 -1
- package/dist/src/utils/Logger.js.map +1 -1
- package/dist/src/utils/SessionStorage.js +0 -1
- package/dist/src/utils/SessionStorage.js.map +1 -1
- package/dist/src/utils/observables.d.ts +1 -0
- package/dist/src/utils/observables.js +5 -0
- package/dist/src/utils/observables.js.map +1 -0
- package/dist/src/utils/operators.js +0 -1
- package/dist/src/utils/operators.js.map +1 -1
- package/dist/src/utils/zodSchemas.d.ts +27 -27
- package/dist/src/utils/zodSchemas.js +3 -3
- package/dist/src/utils/zodSchemas.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/src/events/AddPurchaseEvent.d.ts +0 -5
- package/dist/src/events/AddPurchaseEvent.js +0 -16
- package/dist/src/events/AddPurchaseEvent.js.map +0 -1
package/README.md
CHANGED
|
@@ -17,12 +17,12 @@ yarn add @blux.ai/web-sdk
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
- 필요 변수 :
|
|
20
|
+
- 필요 변수 : `Application ID`, `API 키`
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
const bluxClient = new BluxClient({
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
bluxApplicationId: "BLUX_APPLICATION_ID",
|
|
25
|
+
bluxAPIKey: "BLUX_API_KEY",
|
|
26
26
|
});
|
|
27
27
|
bluxClient.setLogLevel("warning");
|
|
28
28
|
```
|
|
@@ -42,7 +42,7 @@ bluxClient.setLogLevel("warning");
|
|
|
42
42
|
- 회원 유저가 앱을 실행하는 시점에도 `initialize` 메소드 호출 이후에 실행되어야 합니다.
|
|
43
43
|
|
|
44
44
|
```typescript
|
|
45
|
-
bluxClient.signIn("USER ID");
|
|
45
|
+
bluxClient.signIn({ userId: "USER ID" });
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### setUserProperties
|
|
@@ -51,8 +51,10 @@ bluxClient.signIn("USER ID");
|
|
|
51
51
|
|
|
52
52
|
```typescript
|
|
53
53
|
bluxClient.setUserProperties({
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
userProperties: {
|
|
55
|
+
phone_number: "01011112222",
|
|
56
|
+
email_address: "test@example.com",
|
|
57
|
+
},
|
|
56
58
|
});
|
|
57
59
|
```
|
|
58
60
|
|
|
@@ -62,10 +64,11 @@ bluxClient.setUserProperties({
|
|
|
62
64
|
|
|
63
65
|
```typescript
|
|
64
66
|
bluxClient.setCustomUserProperties({
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
customUserProperties: {
|
|
68
|
+
custom_key1: "any_value",
|
|
69
|
+
custom_key2: true,
|
|
70
|
+
custom_key4: 3,
|
|
71
|
+
},
|
|
69
72
|
});
|
|
70
73
|
```
|
|
71
74
|
|
|
@@ -89,7 +92,7 @@ bluxClient.signOut();
|
|
|
89
92
|
```typescript
|
|
90
93
|
bluxClient.sendEvent(
|
|
91
94
|
new AddProductDetailViewEvent({
|
|
92
|
-
|
|
95
|
+
itemId: "ITEM_ID",
|
|
93
96
|
}),
|
|
94
97
|
);
|
|
95
98
|
```
|
|
@@ -103,7 +106,7 @@ bluxClient.sendEvent(
|
|
|
103
106
|
```typescript
|
|
104
107
|
bluxClient.sendEvent(
|
|
105
108
|
new AddLikeEvent({
|
|
106
|
-
|
|
109
|
+
itemId: "ITEM_ID",
|
|
107
110
|
}),
|
|
108
111
|
);
|
|
109
112
|
```
|
|
@@ -117,41 +120,53 @@ bluxClient.sendEvent(
|
|
|
117
120
|
```typescript
|
|
118
121
|
bluxClient.sendEvent(
|
|
119
122
|
new AddCartaddEvent({
|
|
120
|
-
|
|
123
|
+
itemId: "ITEM_ID",
|
|
121
124
|
}),
|
|
122
125
|
);
|
|
123
126
|
```
|
|
124
127
|
|
|
125
128
|
#### 상품 구매
|
|
126
129
|
|
|
127
|
-
: 유저가 제품을 구매했을 때 사용 가능한 이벤트입니다.
|
|
130
|
+
: 유저가 제품을 구매했을 때 사용 가능한 이벤트입니다. paidAmount 파라미터의 경우, 캠페인을 통한 성과 집계에 사용되는 값입니다.
|
|
128
131
|
|
|
129
132
|
---
|
|
130
133
|
|
|
131
|
-
- **_동일 상품 복수 구매_**
|
|
132
|
-
- price 파라미터의 경우, 해당 상품 판매를 통한 총 매출을 계산할 때 활용됩니다. 추천에 의한 매출 기여액 지표를 보여드릴 때 사용되는 값으로 만약 5,000원짜리 상품을 5개 구매하였다면, 25,000 을 입력하시면 됩니다.
|
|
133
|
-
- **_복수 상품 구매_**
|
|
134
|
-
- `AddPurchaseEvent` 객체를 각 상품 구매건에 맞춰서 생성한 후 list 형태로 넘겨주시면 됩니다.
|
|
135
|
-
|
|
136
134
|
```typescript
|
|
137
135
|
bluxClient.sendEvent(
|
|
138
|
-
new
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
new AddOrderEvent({
|
|
137
|
+
orderId: "ORDER_ID",
|
|
138
|
+
paidAmount: 1200,
|
|
139
|
+
orderAmount: 2000,
|
|
140
|
+
items: [
|
|
141
|
+
{
|
|
142
|
+
id: "ITEM_ID_1",
|
|
143
|
+
price: 1000,
|
|
144
|
+
quantity: 1,
|
|
145
|
+
},
|
|
146
|
+
],
|
|
141
147
|
}),
|
|
142
148
|
);
|
|
143
149
|
```
|
|
144
150
|
|
|
145
151
|
```typescript
|
|
146
152
|
// 복수 상품을 구매한 경우
|
|
147
|
-
bluxClient.sendEvent(
|
|
148
|
-
new
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
bluxClient.sendEvent(
|
|
154
|
+
new AddOrderEvent({
|
|
155
|
+
orderId: "ORDER_ID",
|
|
156
|
+
paidAmount: 1200,
|
|
157
|
+
orderAmount: 2000,
|
|
158
|
+
items: [
|
|
159
|
+
{
|
|
160
|
+
id: "ITEM_ID_1",
|
|
161
|
+
price: 1000,
|
|
162
|
+
quantity: 1,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: "ITEM_ID_2",
|
|
166
|
+
price: 2000,
|
|
167
|
+
quantity: 2,
|
|
168
|
+
},
|
|
169
|
+
],
|
|
155
170
|
}),
|
|
156
|
-
|
|
171
|
+
);
|
|
157
172
|
```
|
package/dist/package.json
CHANGED
package/dist/src/BluxClient.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
|
-
import type
|
|
3
|
-
import type { EventRequest } from "./events/types";
|
|
2
|
+
import { DevicePlatform, type APIs } from "./apis/APIs";
|
|
4
3
|
import type { Event as BluxEvent } from "./events/Event";
|
|
5
|
-
import {
|
|
4
|
+
import type { EventRequest } from "./events/types";
|
|
6
5
|
import type { CategoryRec, ItemRec, ItemsRec, UserRec } from "./recs";
|
|
6
|
+
import type { LogLevel } from "./utils/Logger";
|
|
7
7
|
export type SdkInfo = {
|
|
8
|
-
type:
|
|
8
|
+
type: DevicePlatform;
|
|
9
9
|
version: string;
|
|
10
10
|
};
|
|
11
11
|
type BluxUser = {
|
|
12
12
|
id: string;
|
|
13
|
-
|
|
13
|
+
bluxAPIKey: string;
|
|
14
14
|
applicationId: string;
|
|
15
15
|
deviceId?: string;
|
|
16
16
|
userId?: string;
|
|
@@ -20,31 +20,48 @@ export declare class BluxClient {
|
|
|
20
20
|
private readonly sdkInfo;
|
|
21
21
|
readonly bluxUser$: BehaviorSubject<BluxUser | undefined>;
|
|
22
22
|
readonly requestQueue$: BehaviorSubject<EventRequest[]>;
|
|
23
|
-
|
|
24
|
-
private readonly
|
|
23
|
+
readonly inappQueue$: BehaviorSubject<APIs.inappsDispatcher.ResponseData | undefined>;
|
|
24
|
+
private readonly bluxApplicationId;
|
|
25
|
+
private readonly bluxAPIKey;
|
|
25
26
|
private impressedElements;
|
|
26
27
|
private intersectionObservingElements;
|
|
27
28
|
private readonly intersectionObserver;
|
|
28
29
|
private readonly intersectionEntry$;
|
|
29
30
|
private hitElements;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
private postMessageToRN;
|
|
32
|
+
constructor({ bluxApplicationId, bluxAPIKey, }: {
|
|
33
|
+
bluxApplicationId: string;
|
|
34
|
+
bluxAPIKey: string;
|
|
33
35
|
}, completionCallback?: (args: {
|
|
34
36
|
errorMessage?: string;
|
|
35
37
|
success: boolean;
|
|
36
38
|
}) => void);
|
|
37
39
|
private generateApiHeader;
|
|
40
|
+
private handleSendRequest;
|
|
41
|
+
private handleInappEvent;
|
|
42
|
+
private displayInapp;
|
|
38
43
|
private init;
|
|
39
44
|
setLogLevel(logLevel: LogLevel): void;
|
|
40
45
|
private getBluxUserWithTimeout;
|
|
41
|
-
signIn(userId
|
|
46
|
+
signIn({ userId }: {
|
|
47
|
+
userId: string;
|
|
48
|
+
}): Promise<void>;
|
|
42
49
|
signOut(): Promise<void>;
|
|
43
|
-
setUserProperties(userProperties: {
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
setUserProperties({ userProperties, }: {
|
|
51
|
+
userProperties: {
|
|
52
|
+
phone_number?: string;
|
|
53
|
+
email_address?: string;
|
|
54
|
+
marketing_notification_consent?: boolean;
|
|
55
|
+
nighttime_notification_consent?: boolean;
|
|
56
|
+
marketing_notification_sms_consent?: boolean;
|
|
57
|
+
marketing_notification_email_consent?: boolean;
|
|
58
|
+
marketing_notification_push_consent?: boolean;
|
|
59
|
+
marketing_notification_kakao_consent?: boolean;
|
|
60
|
+
};
|
|
61
|
+
}): Promise<void>;
|
|
62
|
+
setCustomUserProperties({ customUserProperties, }: {
|
|
63
|
+
customUserProperties: Record<string, string | boolean | number | null>;
|
|
46
64
|
}): Promise<void>;
|
|
47
|
-
setCustomUserProperties(customUserProperties: Record<string, string | boolean | number | null>): Promise<void>;
|
|
48
65
|
sendEvent(event: BluxEvent | BluxEvent[]): void;
|
|
49
66
|
private urlAndRef$;
|
|
50
67
|
private handleUrlAndRef;
|
package/dist/src/BluxClient.js
CHANGED
|
@@ -1,32 +1,35 @@
|
|
|
1
|
-
import packageJson from "../package.json";
|
|
2
|
-
import { asyncScheduler, BehaviorSubject, catchError, combineLatest, debounceTime, exhaustMap, filter, firstValueFrom, groupBy, map, mergeMap, observeOn, Subject, throwError, timeout, } from "rxjs";
|
|
3
|
-
import { LocalStorage } from "./utils/LocalStorage";
|
|
4
|
-
import { Logger } from "./utils/Logger";
|
|
5
1
|
import axios from "axios";
|
|
6
|
-
import
|
|
2
|
+
import dayjs from "dayjs";
|
|
3
|
+
import { asyncScheduler, BehaviorSubject, catchError, combineLatest, concatMap, debounceTime, exhaustMap, filter, firstValueFrom, from, groupBy, map, mergeMap, NEVER, observeOn, Subject, switchMap, throwError, timeout, timer, withLatestFrom, } from "rxjs";
|
|
4
|
+
import packageJson from "../package.json";
|
|
5
|
+
import { DevicePlatform } from "./apis/APIs";
|
|
6
|
+
import { createCrmEvent } from "./apis/createCrmEvent";
|
|
7
|
+
import { collectEvent } from "./apis/createEvent";
|
|
8
|
+
import { getItemRecommendations } from "./apis/getItemRecommendations";
|
|
9
|
+
import { inappsDispatch } from "./apis/inappsDispatch";
|
|
7
10
|
import { initialize } from "./apis/initialize";
|
|
8
11
|
import { signIn } from "./apis/signIn";
|
|
9
12
|
import { signOut } from "./apis/signOut";
|
|
10
|
-
import { updateUserProperties } from "./apis/updateUserProperties";
|
|
11
13
|
import { updateCustomUserProperties } from "./apis/updateCustomUserProperties";
|
|
12
|
-
import {
|
|
13
|
-
import { DevicePlatform } from "./apis/APIs";
|
|
14
|
-
import { SessionStorage } from "./utils/SessionStorage";
|
|
15
|
-
import { AddClickEvent, AddPageVisitEvent, AddSectionViewEvent, VisitEvent, } from "./events";
|
|
14
|
+
import { updateUserProperties } from "./apis/updateUserProperties";
|
|
16
15
|
import { BLUX_ATTRIBUTES } from "./constants/BLUX_ATTRIBUTES";
|
|
17
|
-
import {
|
|
16
|
+
import { AddClickEvent, AddPageVisitEvent, AddSectionViewEvent, VisitEvent, } from "./events";
|
|
17
|
+
import { LocalStorage } from "./utils/LocalStorage";
|
|
18
|
+
import { Logger } from "./utils/Logger";
|
|
19
|
+
import { onlineAndVisible$ } from "./utils/observables";
|
|
20
|
+
import { filterNullable } from "./utils/operators";
|
|
21
|
+
import { SessionStorage } from "./utils/SessionStorage";
|
|
18
22
|
export class BluxClient {
|
|
19
|
-
api = axios.create(
|
|
20
|
-
baseURL: "https://api.blux.ai/prod",
|
|
21
|
-
});
|
|
23
|
+
api = axios.create();
|
|
22
24
|
sdkInfo = {
|
|
23
|
-
type:
|
|
25
|
+
type: DevicePlatform.browser,
|
|
24
26
|
version: packageJson.version,
|
|
25
27
|
};
|
|
26
28
|
bluxUser$ = new BehaviorSubject(undefined);
|
|
27
29
|
requestQueue$ = new BehaviorSubject([]);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
inappQueue$ = new BehaviorSubject(undefined);
|
|
31
|
+
bluxApplicationId;
|
|
32
|
+
bluxAPIKey;
|
|
30
33
|
// Impression 관련 변수
|
|
31
34
|
impressedElements = [];
|
|
32
35
|
intersectionObservingElements = [];
|
|
@@ -38,39 +41,47 @@ export class BluxClient {
|
|
|
38
41
|
intersectionEntry$ = new Subject();
|
|
39
42
|
// Hit 관련 변수
|
|
40
43
|
hitElements = [];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
// RN 브릿지 함수를 위한 함수
|
|
45
|
+
postMessageToRN(action, payload) {
|
|
46
|
+
if (typeof window !== "undefined" &&
|
|
47
|
+
window.ReactNativeWebView?.postMessage) {
|
|
48
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ action, payload }));
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
constructor({ bluxApplicationId, bluxAPIKey, }, completionCallback) {
|
|
54
|
+
this.bluxApplicationId = bluxApplicationId;
|
|
55
|
+
this.bluxAPIKey = bluxAPIKey;
|
|
56
|
+
const baseUrl = window?._BLUX_SDK_?.baseUrl ?? "https://api.blux.ai/prod";
|
|
57
|
+
this.api.defaults.baseURL = baseUrl;
|
|
58
|
+
onlineAndVisible$
|
|
59
|
+
.pipe(switchMap((active) => (active ? timer(0, 5000) : NEVER)), withLatestFrom(this.bluxUser$), map(([_, bluxUser]) => bluxUser), filterNullable(), exhaustMap((bluxUser) => this.handleInappEvent(bluxUser)))
|
|
60
|
+
.subscribe();
|
|
44
61
|
combineLatest([this.requestQueue$, this.bluxUser$.pipe(filterNullable())])
|
|
45
62
|
.pipe(filter(([requests]) => requests.length > 0), exhaustMap(async ([requests, bluxUser]) => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
blux_id: bluxUser.id,
|
|
59
|
-
device_id: bluxUser.deviceId,
|
|
60
|
-
})),
|
|
61
|
-
}, this.generateApiHeader(bluxUser));
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
// todo : retry
|
|
65
|
-
Logger.error(error, { tags: { from: "request-events-api" } });
|
|
66
|
-
}
|
|
67
|
-
return requests.map((r) => r.id); // todo: return successed requests only
|
|
63
|
+
const events = requests.map((request) => ({
|
|
64
|
+
...request,
|
|
65
|
+
internal_event_properties: {
|
|
66
|
+
...request.internal_event_properties,
|
|
67
|
+
url: `${this.urlAndRef$.value?.url ?? null}`,
|
|
68
|
+
ref: `${this.urlAndRef$.value?.ref ?? null}`,
|
|
69
|
+
},
|
|
70
|
+
blux_id: bluxUser.id,
|
|
71
|
+
device_id: bluxUser.deviceId,
|
|
72
|
+
}));
|
|
73
|
+
await this.handleSendRequest({ bluxUser, events });
|
|
74
|
+
return requests.map((r) => r.id); // TODO: @all return successed requests only
|
|
68
75
|
}), map((requestIdsSucceeded) => this.requestQueue$.value.filter((request) => !requestIdsSucceeded.includes(request.id))), observeOn(asyncScheduler))
|
|
69
76
|
.subscribe(this.requestQueue$);
|
|
70
77
|
this.bluxUser$.subscribe((bluxUser) => {
|
|
71
78
|
if (bluxUser)
|
|
72
79
|
SessionStorage.setBluxUserId(bluxUser.id);
|
|
73
80
|
});
|
|
81
|
+
this.inappQueue$
|
|
82
|
+
.pipe(filterNullable())
|
|
83
|
+
.pipe(concatMap((inapp) => from(this.displayInapp(inapp))))
|
|
84
|
+
.subscribe();
|
|
74
85
|
this.init()
|
|
75
86
|
.then(() => {
|
|
76
87
|
completionCallback?.({ success: true });
|
|
@@ -79,17 +90,123 @@ export class BluxClient {
|
|
|
79
90
|
completionCallback?.({ success: false, errorMessage: error.message });
|
|
80
91
|
});
|
|
81
92
|
}
|
|
82
|
-
generateApiHeader({
|
|
93
|
+
generateApiHeader({ bluxAPIKey }) {
|
|
83
94
|
return {
|
|
84
|
-
Authorization:
|
|
95
|
+
Authorization: bluxAPIKey,
|
|
85
96
|
};
|
|
86
97
|
}
|
|
98
|
+
async handleSendRequest({ bluxUser, events, }) {
|
|
99
|
+
try {
|
|
100
|
+
await collectEvent(this.api, {
|
|
101
|
+
blux_user_id: bluxUser.id,
|
|
102
|
+
application_id: bluxUser.applicationId,
|
|
103
|
+
}, {
|
|
104
|
+
events,
|
|
105
|
+
}, this.generateApiHeader(bluxUser));
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
Logger.error(error, { tags: { from: "request-events-api" } });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async handleInappEvent(bluxUser) {
|
|
112
|
+
try {
|
|
113
|
+
const { data } = await inappsDispatch(this.api, {
|
|
114
|
+
application_id: bluxUser.applicationId,
|
|
115
|
+
}, {
|
|
116
|
+
blux_user_id: bluxUser.id,
|
|
117
|
+
device_id: bluxUser.deviceId ?? "",
|
|
118
|
+
platform: this.sdkInfo.type,
|
|
119
|
+
}, this.generateApiHeader(bluxUser));
|
|
120
|
+
this.inappQueue$.next(data);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
Logger.error(error, { tags: { from: "request-inapps-api" } });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async displayInapp(inapp) {
|
|
127
|
+
return new Promise((resolve) => {
|
|
128
|
+
if (!inapp.shouldDisplay)
|
|
129
|
+
return resolve(true);
|
|
130
|
+
const hideTimestamp = LocalStorage.getInappHideTimestamp(inapp.inappId);
|
|
131
|
+
const isShouldSkip = hideTimestamp !== null && dayjs().isBefore(dayjs(hideTimestamp));
|
|
132
|
+
if (isShouldSkip)
|
|
133
|
+
return resolve(true);
|
|
134
|
+
const iframeElement = document.createElement("iframe");
|
|
135
|
+
const params = new URLSearchParams({
|
|
136
|
+
inapp_id: inapp.inappId,
|
|
137
|
+
application_id: this.bluxApplicationId,
|
|
138
|
+
stage: "prod",
|
|
139
|
+
});
|
|
140
|
+
iframeElement.src = `${inapp.baseUrl}?${params.toString()}`;
|
|
141
|
+
iframeElement.style.position = "fixed";
|
|
142
|
+
iframeElement.style.width = `${window.innerWidth}px`;
|
|
143
|
+
iframeElement.style.height = `${window.innerHeight}px`;
|
|
144
|
+
iframeElement.style.top = "0";
|
|
145
|
+
iframeElement.style.left = "0";
|
|
146
|
+
iframeElement.style.zIndex = "9999";
|
|
147
|
+
iframeElement.id = `blux-inapp-${inapp.inappId}`;
|
|
148
|
+
document.body.appendChild(iframeElement);
|
|
149
|
+
const handleViewportChange = () => {
|
|
150
|
+
const width = window.visualViewport?.width ?? window.innerWidth;
|
|
151
|
+
const height = window.visualViewport?.height ?? window.innerHeight;
|
|
152
|
+
const left = window.visualViewport?.offsetLeft ?? 0;
|
|
153
|
+
const top = window.visualViewport?.offsetTop ?? 0;
|
|
154
|
+
iframeElement.style.width = `${width}px`;
|
|
155
|
+
iframeElement.style.height = `${height}px`;
|
|
156
|
+
iframeElement.style.left = `${left}px`;
|
|
157
|
+
iframeElement.style.top = `${top}px`;
|
|
158
|
+
};
|
|
159
|
+
const handleMessage = (event) => {
|
|
160
|
+
const message = event.data;
|
|
161
|
+
if (message.action === "hide") {
|
|
162
|
+
const { days_to_hide } = message.data;
|
|
163
|
+
if (days_to_hide !== 0) {
|
|
164
|
+
const expiresAt = dayjs().add(days_to_hide, "days").valueOf();
|
|
165
|
+
LocalStorage.setInappHideTimestamp(inapp.inappId, expiresAt);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (message.action === "link") {
|
|
169
|
+
const bluxUser = this.bluxUser$.getValue();
|
|
170
|
+
if (bluxUser) {
|
|
171
|
+
createCrmEvent(this.api, {
|
|
172
|
+
application_id: this.bluxApplicationId,
|
|
173
|
+
}, {
|
|
174
|
+
notification_id: inapp.notificationId,
|
|
175
|
+
crm_event_type: "inapp_opened",
|
|
176
|
+
captured_at: new Date().toISOString(),
|
|
177
|
+
}, this.generateApiHeader(bluxUser));
|
|
178
|
+
}
|
|
179
|
+
if (message.data.is_blux_landing) {
|
|
180
|
+
// TODO: @all 스키마상에는 개인화 랜딩이 존재하나, 콘솔에는 필드가 없음 -> 추후 이에 따른 핸들링이 필요함
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
window.open(message.data.url, "_blank");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
iframeElement.remove();
|
|
187
|
+
window.removeEventListener("message", handleMessage);
|
|
188
|
+
window.visualViewport?.removeEventListener("resize", handleViewportChange);
|
|
189
|
+
window.visualViewport?.removeEventListener("scroll", handleViewportChange);
|
|
190
|
+
resolve(inapp.inappId);
|
|
191
|
+
};
|
|
192
|
+
window.visualViewport?.addEventListener("resize", handleViewportChange);
|
|
193
|
+
window.visualViewport?.addEventListener("scroll", handleViewportChange);
|
|
194
|
+
window.addEventListener("message", handleMessage);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
87
197
|
async init() {
|
|
198
|
+
// React Native에서 처리하도록 요청을 보냈다면 웹에서는 API 호출하지 않음
|
|
199
|
+
if (this.postMessageToRN("initialize", {
|
|
200
|
+
bluxApplicationId: this.bluxApplicationId,
|
|
201
|
+
bluxAPIKey: this.bluxAPIKey,
|
|
202
|
+
})) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
88
205
|
const blux_user_id = new URLSearchParams(window.location.search).get("blux_user_id");
|
|
89
206
|
const isBluxUserIdExistInSessionStorage = SessionStorage.getBluxUserId();
|
|
90
207
|
if (!isBluxUserIdExistInSessionStorage)
|
|
91
208
|
this.sendEvent(new VisitEvent({}));
|
|
92
|
-
Logger.debug(`Init with application id: ${this.
|
|
209
|
+
Logger.debug(`Init with application id: ${this.bluxApplicationId}`);
|
|
93
210
|
const deviceId = LocalStorage.getDeviceId();
|
|
94
211
|
if (!deviceId) {
|
|
95
212
|
Logger.debug("No saved Device ID, register a new one.");
|
|
@@ -129,7 +246,7 @@ export class BluxClient {
|
|
|
129
246
|
}));
|
|
130
247
|
this.impressedElements.push(entry.target);
|
|
131
248
|
});
|
|
132
|
-
const { data } = await initialize(this.api, { application_id: this.
|
|
249
|
+
const { data } = await initialize(this.api, { application_id: this.bluxApplicationId }, {
|
|
133
250
|
isVisitHandlingInSdk: true,
|
|
134
251
|
device_id: deviceId ?? undefined,
|
|
135
252
|
country_code: navigator.language.split("-")[1],
|
|
@@ -142,14 +259,14 @@ export class BluxClient {
|
|
|
142
259
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
143
260
|
blux_user_id: blux_user_id ?? undefined,
|
|
144
261
|
}, this.generateApiHeader({
|
|
145
|
-
|
|
262
|
+
bluxAPIKey: this.bluxAPIKey,
|
|
146
263
|
}));
|
|
147
264
|
if (data.device_id)
|
|
148
265
|
LocalStorage.setDeviceId(data.device_id);
|
|
149
266
|
this.bluxUser$.next({
|
|
150
267
|
id: data.blux_user_id,
|
|
151
|
-
|
|
152
|
-
applicationId: this.
|
|
268
|
+
bluxAPIKey: this.bluxAPIKey,
|
|
269
|
+
applicationId: this.bluxApplicationId,
|
|
153
270
|
deviceId: data.device_id,
|
|
154
271
|
});
|
|
155
272
|
}
|
|
@@ -164,7 +281,12 @@ export class BluxClient {
|
|
|
164
281
|
})));
|
|
165
282
|
return bluxUser;
|
|
166
283
|
}
|
|
167
|
-
async signIn(userId) {
|
|
284
|
+
async signIn({ userId }) {
|
|
285
|
+
// React Native에서 처리하도록 요청을 보냈다면 웹에서는 API 호출하지 않음
|
|
286
|
+
if (this.postMessageToRN("signIn", { userId })) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
// React Native WebView가 아닌 경우 웹에서 직접 처리
|
|
168
290
|
try {
|
|
169
291
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
170
292
|
const { data: { blux_user_id: bluxIdInResponse }, } = await signIn(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { user_id: userId, device_id: bluxUser.deviceId }, this.generateApiHeader(bluxUser));
|
|
@@ -181,6 +303,11 @@ export class BluxClient {
|
|
|
181
303
|
}
|
|
182
304
|
}
|
|
183
305
|
async signOut() {
|
|
306
|
+
// React Native에서 처리하도록 요청을 보냈다면 웹에서는 API 호출하지 않음
|
|
307
|
+
if (this.postMessageToRN("signOut")) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// React Native WebView가 아닌 경우 웹에서 직접 처리
|
|
184
311
|
try {
|
|
185
312
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
186
313
|
const { data: { blux_user_id: bluxIdInResponse }, } = await signOut(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { device_id: bluxUser.deviceId }, this.generateApiHeader(bluxUser));
|
|
@@ -194,7 +321,12 @@ export class BluxClient {
|
|
|
194
321
|
Logger.error(error, { tags: { from: "signOut" } });
|
|
195
322
|
}
|
|
196
323
|
}
|
|
197
|
-
async setUserProperties(userProperties) {
|
|
324
|
+
async setUserProperties({ userProperties, }) {
|
|
325
|
+
// React Native에서 처리하도록 요청을 보냈다면 웹에서는 API 호출하지 않음
|
|
326
|
+
if (this.postMessageToRN("setUserProperties", { userProperties })) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
// React Native WebView가 아닌 경우 웹에서 직접 처리
|
|
198
330
|
try {
|
|
199
331
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
200
332
|
await updateUserProperties(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { properties: userProperties }, this.generateApiHeader(bluxUser));
|
|
@@ -203,7 +335,12 @@ export class BluxClient {
|
|
|
203
335
|
Logger.error(error, { tags: { from: "setUserProperties" } });
|
|
204
336
|
}
|
|
205
337
|
}
|
|
206
|
-
async setCustomUserProperties(customUserProperties) {
|
|
338
|
+
async setCustomUserProperties({ customUserProperties, }) {
|
|
339
|
+
// React Native에서 처리하도록 요청을 보냈다면 웹에서는 API 호출하지 않음
|
|
340
|
+
if (this.postMessageToRN("setCustomUserProperties", { customUserProperties })) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// React Native WebView가 아닌 경우 웹에서 직접 처리
|
|
207
344
|
try {
|
|
208
345
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
209
346
|
await updateCustomUserProperties(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { properties: customUserProperties }, this.generateApiHeader(bluxUser));
|
|
@@ -214,6 +351,11 @@ export class BluxClient {
|
|
|
214
351
|
}
|
|
215
352
|
sendEvent(event) {
|
|
216
353
|
const requests = (Array.isArray(event) ? event : [event]).map((event) => event.request);
|
|
354
|
+
// React Native에서 처리하도록 요청을 보냈다면 웹에서는 API 호출하지 않음
|
|
355
|
+
if (this.postMessageToRN("sendEvent", { requests })) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
// React Native WebView가 아닌 경우 웹에서 직접 처리
|
|
217
359
|
this.requestQueue$.next([
|
|
218
360
|
...this.requestQueue$.value,
|
|
219
361
|
...requests.filter((request) => !this.requestQueue$.value.map((r) => r.id).includes(request.id)),
|
|
@@ -276,7 +418,7 @@ export class BluxClient {
|
|
|
276
418
|
}
|
|
277
419
|
if (!this.hitElements.includes(targetItemElement)) {
|
|
278
420
|
this.sendEvent(new AddClickEvent({
|
|
279
|
-
|
|
421
|
+
itemId,
|
|
280
422
|
tracking: {
|
|
281
423
|
id: trackingId,
|
|
282
424
|
type: "hit",
|