@suprsend/web-sdk 1.0.0 → 1.2.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/dist/cdn_bundle.js +1 -1
- package/dist/cjs_bundle.js +1 -1
- package/package.json +5 -4
- package/src/config.js +3 -2
- package/src/encryption.js +12 -5
- package/src/index.d.ts +113 -0
- package/src/index.js +10 -2
- package/src/preferences.js +474 -0
- package/src/user.js +3 -1
- package/src/utils.js +30 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suprsend/web-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "This is sdk used to integrate suprsend functionality in javascript applications",
|
|
5
5
|
"main": "dist/cjs_bundle.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
8
|
"build": "rm -rf dist && webpack --env module_type=commonjs --env filename=cjs_bundle.js && webpack --env module_type=window --env filename=cdn_bundle.js",
|
|
9
|
-
"
|
|
9
|
+
"publish_sdk": "npm run build && npm publish"
|
|
10
10
|
},
|
|
11
11
|
"keywords": [
|
|
12
12
|
"suprsend",
|
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
"@babel/core": "^7.18.5",
|
|
28
28
|
"@babel/preset-env": "^7.18.2",
|
|
29
29
|
"babel-loader": "^8.2.5",
|
|
30
|
-
"webpack": "^5.
|
|
30
|
+
"webpack": "^5.76.0",
|
|
31
31
|
"webpack-cli": "^4.8.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"libphonenumber-js": "^1.10.7"
|
|
34
|
+
"libphonenumber-js": "^1.10.7",
|
|
35
|
+
"mitt": "^3.0.0"
|
|
35
36
|
}
|
|
36
37
|
}
|
package/src/config.js
CHANGED
|
@@ -4,9 +4,10 @@ const config = {
|
|
|
4
4
|
api_url: "https://hub.suprsend.com",
|
|
5
5
|
sdk_version: package_data.version,
|
|
6
6
|
batch_size: 20,
|
|
7
|
-
flush_interval: 3000,
|
|
7
|
+
flush_interval: 3000, // in ms
|
|
8
8
|
service_worker_file: "serviceworker.js",
|
|
9
|
-
sw_delay: 5000, //in ms,
|
|
9
|
+
sw_delay: 5000, // in ms,
|
|
10
|
+
preference_debounce: 1000, // in ms
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
export default config;
|
package/src/encryption.js
CHANGED
|
@@ -236,15 +236,22 @@ const getUtf8Bytes = (str) =>
|
|
|
236
236
|
[...unescape(encodeURIComponent(str))].map((c) => c.charCodeAt(0))
|
|
237
237
|
);
|
|
238
238
|
|
|
239
|
-
export default async function create_signature(
|
|
239
|
+
export default async function create_signature(
|
|
240
|
+
str,
|
|
241
|
+
date,
|
|
242
|
+
method,
|
|
243
|
+
route = `/${constants.api_events_route}`
|
|
244
|
+
) {
|
|
240
245
|
if (!window.crypto) {
|
|
241
246
|
return;
|
|
242
247
|
}
|
|
243
248
|
const key = config.signing_key;
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
249
|
+
const content_type = "application/json";
|
|
250
|
+
let md5_str = "";
|
|
251
|
+
if (str) {
|
|
252
|
+
md5_str = MD5(str);
|
|
253
|
+
}
|
|
254
|
+
const message = `${method}\n${md5_str}\n${content_type}\n${date}\n${route}`;
|
|
248
255
|
const keyBytes = getUtf8Bytes(key);
|
|
249
256
|
const messageBytes = getUtf8Bytes(message);
|
|
250
257
|
|
package/src/index.d.ts
CHANGED
|
@@ -1,8 +1,120 @@
|
|
|
1
|
+
import { Emitter } from "mitt";
|
|
2
|
+
|
|
1
3
|
interface Dictionary {
|
|
2
4
|
[key: string]: any;
|
|
3
5
|
}
|
|
4
6
|
|
|
7
|
+
export enum PreferenceOptions {
|
|
8
|
+
OPT_IN = "opt_in",
|
|
9
|
+
OPT_OUT = "opt_out",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export enum ChannelLevelPreferenceOptions {
|
|
13
|
+
ALL = "all",
|
|
14
|
+
REQUIRED = "required",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type EmitterEvents = {
|
|
18
|
+
preferences_updated?: null;
|
|
19
|
+
preferences_error: PreferenceErrorData;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
interface CategoryChannel {
|
|
23
|
+
channel: string;
|
|
24
|
+
preference: PreferenceOptions;
|
|
25
|
+
is_editable: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Category {
|
|
29
|
+
name: string;
|
|
30
|
+
category: string;
|
|
31
|
+
description?: string | null;
|
|
32
|
+
preference: PreferenceOptions;
|
|
33
|
+
is_editable: boolean;
|
|
34
|
+
channels?: CategoryChannel[] | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface Section {
|
|
38
|
+
name?: string | null;
|
|
39
|
+
description?: string | null;
|
|
40
|
+
subcategories?: Category[] | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ChannelPreference {
|
|
44
|
+
channel: string;
|
|
45
|
+
is_restricted: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface PreferenceData {
|
|
49
|
+
sections: Section[] | null;
|
|
50
|
+
channel_preferences: ChannelPreference[] | null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface PreferenceErrorData {
|
|
54
|
+
error: boolean;
|
|
55
|
+
api_error?: boolean;
|
|
56
|
+
message: string;
|
|
57
|
+
status_code?: number | null;
|
|
58
|
+
error_obj?: Error | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface GetPreferencesResponse extends PreferenceData, PreferenceErrorData {}
|
|
62
|
+
|
|
63
|
+
interface GetCategoriesResponse extends PreferenceErrorData {
|
|
64
|
+
meta: { count: number; limit: number; offset: number };
|
|
65
|
+
results: Category[] | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface GetOverAllChannelPreferencesResponse extends PreferenceErrorData {
|
|
69
|
+
channel_preferences: ChannelPreference[] | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface Preferences {
|
|
73
|
+
data: PreferenceData;
|
|
74
|
+
|
|
75
|
+
get_preferences(args?: {
|
|
76
|
+
brand_id?: string;
|
|
77
|
+
}): Promise<GetPreferencesResponse>;
|
|
78
|
+
|
|
79
|
+
get_categories(args?: {
|
|
80
|
+
brand_id?: string;
|
|
81
|
+
limit?: number;
|
|
82
|
+
offset?: number;
|
|
83
|
+
}): Promise<GetCategoriesResponse>;
|
|
84
|
+
|
|
85
|
+
get_category(
|
|
86
|
+
category: string,
|
|
87
|
+
args?: { brand_id?: string }
|
|
88
|
+
): Promise<Category>;
|
|
89
|
+
|
|
90
|
+
get_overall_channel_preferences(): Promise<GetOverAllChannelPreferencesResponse>;
|
|
91
|
+
|
|
92
|
+
update_category_preference(
|
|
93
|
+
category: string,
|
|
94
|
+
preference: PreferenceOptions,
|
|
95
|
+
args?: {
|
|
96
|
+
brand_id?: string;
|
|
97
|
+
}
|
|
98
|
+
): void | PreferenceErrorData;
|
|
99
|
+
|
|
100
|
+
update_channel_preference_in_category(
|
|
101
|
+
channel: string,
|
|
102
|
+
preference: PreferenceOptions,
|
|
103
|
+
category: string,
|
|
104
|
+
args?: {
|
|
105
|
+
brand_id?: string;
|
|
106
|
+
}
|
|
107
|
+
): void | PreferenceErrorData;
|
|
108
|
+
|
|
109
|
+
update_overall_channel_preference(
|
|
110
|
+
channel: string,
|
|
111
|
+
preference: ChannelLevelPreferenceOptions
|
|
112
|
+
): void | PreferenceErrorData;
|
|
113
|
+
}
|
|
114
|
+
|
|
5
115
|
interface User {
|
|
116
|
+
preferences: Preferences;
|
|
117
|
+
|
|
6
118
|
set(key: string, value: any): void;
|
|
7
119
|
set(prop: Dictionary): void;
|
|
8
120
|
|
|
@@ -56,6 +168,7 @@ export interface SuprSend {
|
|
|
56
168
|
|
|
57
169
|
user: User;
|
|
58
170
|
web_push: WebPush;
|
|
171
|
+
emitter: Emitter<EmitterEvents>;
|
|
59
172
|
}
|
|
60
173
|
|
|
61
174
|
declare const suprsend: SuprSend;
|
package/src/index.js
CHANGED
|
@@ -4,6 +4,11 @@ import User from "./user";
|
|
|
4
4
|
import WebPush from "./web_push";
|
|
5
5
|
import { constants, internal_events } from "./constants";
|
|
6
6
|
import { SSConfigurationError } from "./errors";
|
|
7
|
+
import mitt from "mitt";
|
|
8
|
+
export {
|
|
9
|
+
PreferenceOptions,
|
|
10
|
+
ChannelLevelPreferenceOptions,
|
|
11
|
+
} from "./preferences";
|
|
7
12
|
|
|
8
13
|
var suprSendInstance;
|
|
9
14
|
export var initialisedAt;
|
|
@@ -22,8 +27,11 @@ class SuprSend {
|
|
|
22
27
|
utils.set_cookie(constants.distinct_id, distinct_id);
|
|
23
28
|
}
|
|
24
29
|
suprSendInstance.distinct_id = distinct_id;
|
|
25
|
-
|
|
30
|
+
|
|
31
|
+
this.emitter = mitt();
|
|
32
|
+
this.user = new User(suprSendInstance, this.emitter);
|
|
26
33
|
this.web_push = new WebPush(suprSendInstance);
|
|
34
|
+
|
|
27
35
|
this.web_push.update_subscription();
|
|
28
36
|
SuprSend._set_env_properties();
|
|
29
37
|
if (!initialisedAt) {
|
|
@@ -165,7 +173,7 @@ class SuprSend {
|
|
|
165
173
|
_user_identified: false,
|
|
166
174
|
};
|
|
167
175
|
utils.remove_local_storage_item(constants.super_properties_key);
|
|
168
|
-
this.user = new User(suprSendInstance);
|
|
176
|
+
this.user = new User(suprSendInstance, this.emitter);
|
|
169
177
|
this.web_push = new WebPush(suprSendInstance);
|
|
170
178
|
SuprSend._set_env_properties();
|
|
171
179
|
}
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import create_signature from "./encryption";
|
|
2
|
+
import config from "./config";
|
|
3
|
+
import utils from "./utils";
|
|
4
|
+
|
|
5
|
+
export const PreferenceOptions = { OPT_IN: "opt_in", OPT_OUT: "opt_out" };
|
|
6
|
+
export const ChannelLevelPreferenceOptions = {
|
|
7
|
+
ALL: "all",
|
|
8
|
+
REQUIRED: "required",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class Preferences {
|
|
12
|
+
constructor(instance, emitter) {
|
|
13
|
+
this.ss_instance = instance;
|
|
14
|
+
this._preference_data;
|
|
15
|
+
this._preference_args;
|
|
16
|
+
this._emitter = emitter;
|
|
17
|
+
|
|
18
|
+
this._debounced_update_category_preferences = utils.debounce_by_type(
|
|
19
|
+
this._update_category_preferences,
|
|
20
|
+
config.preference_debounce
|
|
21
|
+
);
|
|
22
|
+
this._debounced_update_channel_preferences = utils.debounce_by_type(
|
|
23
|
+
this._update_channel_preferences,
|
|
24
|
+
config.preference_debounce
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_validate_query_params(query_params = {}) {
|
|
29
|
+
let validated_params = {};
|
|
30
|
+
for (let key in query_params) {
|
|
31
|
+
if (query_params[key]) {
|
|
32
|
+
validated_params[key] = query_params[key];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return validated_params;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async _get_request(route = "", query_params = {}) {
|
|
39
|
+
const preference_base_url = `/v1/subscriber/${this.ss_instance.distinct_id}`;
|
|
40
|
+
const validated_query_params = this._validate_query_params(query_params);
|
|
41
|
+
const query_params_string = new URLSearchParams(
|
|
42
|
+
validated_query_params
|
|
43
|
+
).toString();
|
|
44
|
+
|
|
45
|
+
const full_url_path = query_params_string
|
|
46
|
+
? `${preference_base_url}/${route}/?${query_params_string}`
|
|
47
|
+
: `${preference_base_url}/${route}`;
|
|
48
|
+
|
|
49
|
+
const requested_date = new Date().toGMTString();
|
|
50
|
+
const signature = await create_signature(
|
|
51
|
+
"",
|
|
52
|
+
requested_date,
|
|
53
|
+
"GET",
|
|
54
|
+
full_url_path
|
|
55
|
+
);
|
|
56
|
+
const authorization = signature
|
|
57
|
+
? `${config.env_key}:${signature}`
|
|
58
|
+
: config.env_key;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const resp = await fetch(`${config.api_url}${full_url_path}`, {
|
|
62
|
+
headers: {
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
Authorization: authorization,
|
|
65
|
+
"x-amz-date": requested_date,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
if (resp.ok) {
|
|
69
|
+
const respData = resp.json();
|
|
70
|
+
return respData;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
error: true,
|
|
74
|
+
api_error: true,
|
|
75
|
+
status_code: resp.status,
|
|
76
|
+
message: resp.statusText,
|
|
77
|
+
error_obj: null,
|
|
78
|
+
};
|
|
79
|
+
} catch (e) {
|
|
80
|
+
return {
|
|
81
|
+
error: true,
|
|
82
|
+
api_error: false,
|
|
83
|
+
status_code: null,
|
|
84
|
+
message: e.message,
|
|
85
|
+
error_obj: e,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async _update_request(body, route, query_params) {
|
|
91
|
+
const preference_base_url = `/v1/subscriber/${this.ss_instance.distinct_id}`;
|
|
92
|
+
const validated_query_params = this._validate_query_params(query_params);
|
|
93
|
+
const query_params_string = new URLSearchParams(
|
|
94
|
+
validated_query_params
|
|
95
|
+
).toString();
|
|
96
|
+
|
|
97
|
+
const full_url_path = query_params_string
|
|
98
|
+
? `${preference_base_url}/${route}/?${query_params_string}`
|
|
99
|
+
: `${preference_base_url}/${route}`;
|
|
100
|
+
|
|
101
|
+
const requested_date = new Date().toGMTString();
|
|
102
|
+
const bodyString = JSON.stringify(body);
|
|
103
|
+
const signature = await create_signature(
|
|
104
|
+
bodyString,
|
|
105
|
+
requested_date,
|
|
106
|
+
"POST",
|
|
107
|
+
full_url_path
|
|
108
|
+
);
|
|
109
|
+
const authorization = signature
|
|
110
|
+
? `${config.env_key}:${signature}`
|
|
111
|
+
: config.env_key;
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const resp = await fetch(`${config.api_url}${full_url_path}`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
body: bodyString,
|
|
117
|
+
headers: {
|
|
118
|
+
"Content-Type": "application/json",
|
|
119
|
+
Authorization: authorization,
|
|
120
|
+
"x-amz-date": requested_date,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
if (resp.ok) {
|
|
124
|
+
const respData = resp.json();
|
|
125
|
+
return respData;
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
error: true,
|
|
129
|
+
api_error: true,
|
|
130
|
+
status_code: resp.status,
|
|
131
|
+
message: resp.statusText,
|
|
132
|
+
error_obj: null,
|
|
133
|
+
};
|
|
134
|
+
} catch (e) {
|
|
135
|
+
return {
|
|
136
|
+
error: true,
|
|
137
|
+
api_error: false,
|
|
138
|
+
status_code: null,
|
|
139
|
+
message: e.message,
|
|
140
|
+
error_obj: e,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
_update_category_preferences = async (
|
|
146
|
+
category = "",
|
|
147
|
+
body = {},
|
|
148
|
+
subcategory,
|
|
149
|
+
args = {}
|
|
150
|
+
) => {
|
|
151
|
+
let url_path = `category/${category}`;
|
|
152
|
+
const response = await this._update_request(body, url_path, args);
|
|
153
|
+
if (response?.error) {
|
|
154
|
+
this._emitter.emit("preferences_error", response);
|
|
155
|
+
} else {
|
|
156
|
+
Object.assign(subcategory, response);
|
|
157
|
+
this._emitter.emit("preferences_updated");
|
|
158
|
+
}
|
|
159
|
+
return response;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
_update_channel_preferences = async (body = {}) => {
|
|
163
|
+
let url_path = "channel_preference";
|
|
164
|
+
const response = await this._update_request(body, url_path);
|
|
165
|
+
if (response?.error) {
|
|
166
|
+
this._emitter.emit("preferences_error", response);
|
|
167
|
+
} else {
|
|
168
|
+
await this.get_preferences(this._preference_args);
|
|
169
|
+
this._emitter.emit("preferences_updated");
|
|
170
|
+
}
|
|
171
|
+
return response;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
set data(value) {
|
|
175
|
+
this._preference_data = value;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
get data() {
|
|
179
|
+
return this._preference_data;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async get_preferences(args = {}) {
|
|
183
|
+
let url_path = "full_preference";
|
|
184
|
+
let query_params = { brand_id: args?.brand_id };
|
|
185
|
+
|
|
186
|
+
const response = await this._get_request(url_path, query_params);
|
|
187
|
+
if (!response?.error) {
|
|
188
|
+
this.data = response;
|
|
189
|
+
}
|
|
190
|
+
return response;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async get_categories(args = {}) {
|
|
194
|
+
let url_path = "category";
|
|
195
|
+
const query_params = {
|
|
196
|
+
brand_id: args?.brand_id,
|
|
197
|
+
limit: args?.limit,
|
|
198
|
+
offset: args?.offset,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const response = await this._get_request(url_path, query_params);
|
|
202
|
+
return response;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async get_category(category = "", args = {}) {
|
|
206
|
+
if (!category) {
|
|
207
|
+
return {
|
|
208
|
+
error: true,
|
|
209
|
+
message: "Category parameter is missing",
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let url_path = `category/${category}`;
|
|
214
|
+
let query_params = { brand_id: args?.brand_id };
|
|
215
|
+
|
|
216
|
+
const response = await this._get_request(url_path, query_params);
|
|
217
|
+
return response;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async get_overall_channel_preferences() {
|
|
221
|
+
let url_path = `channel_preference`;
|
|
222
|
+
const response = await this._get_request(url_path);
|
|
223
|
+
return response;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
update_category_preference(category = "", preference = "", args = {}) {
|
|
227
|
+
if (
|
|
228
|
+
!category ||
|
|
229
|
+
![PreferenceOptions.OPT_IN, PreferenceOptions.OPT_OUT].includes(
|
|
230
|
+
preference
|
|
231
|
+
)
|
|
232
|
+
) {
|
|
233
|
+
return {
|
|
234
|
+
error: true,
|
|
235
|
+
message: !category
|
|
236
|
+
? "Category parameter is missing"
|
|
237
|
+
: "Preference parameter is invalid",
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!this.data) {
|
|
242
|
+
return {
|
|
243
|
+
error: true,
|
|
244
|
+
message: "Call get_preferences method before performing action",
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let category_data;
|
|
249
|
+
let data_updated = false;
|
|
250
|
+
|
|
251
|
+
// optimistic update in local store
|
|
252
|
+
for (let section of this.data.sections) {
|
|
253
|
+
let abort = false;
|
|
254
|
+
for (let subcategory of section.subcategories) {
|
|
255
|
+
if (subcategory.category === category) {
|
|
256
|
+
category_data = subcategory;
|
|
257
|
+
if (subcategory.is_editable) {
|
|
258
|
+
if (subcategory.preference !== preference) {
|
|
259
|
+
subcategory.preference = preference;
|
|
260
|
+
data_updated = true;
|
|
261
|
+
abort = true;
|
|
262
|
+
break;
|
|
263
|
+
} else {
|
|
264
|
+
// console.log(`category is already ${status}ed`);
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
return {
|
|
268
|
+
error: true,
|
|
269
|
+
message: "Category preference is not editable",
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (abort) break;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!category_data) {
|
|
278
|
+
return {
|
|
279
|
+
error: true,
|
|
280
|
+
message: "Category is not found",
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!data_updated) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const opt_out_channels = [];
|
|
289
|
+
category_data.channels.forEach((channel) => {
|
|
290
|
+
if (channel.preference === PreferenceOptions.OPT_OUT) {
|
|
291
|
+
opt_out_channels.push(channel.channel);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const request_payload = {
|
|
296
|
+
preference: category_data.preference,
|
|
297
|
+
opt_out_channels,
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
this._debounced_update_category_preferences(
|
|
301
|
+
category,
|
|
302
|
+
category,
|
|
303
|
+
request_payload,
|
|
304
|
+
category_data,
|
|
305
|
+
{ brand_id: args?.brand_id }
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
update_channel_preference_in_category(
|
|
310
|
+
channel = "",
|
|
311
|
+
preference = "",
|
|
312
|
+
category = "",
|
|
313
|
+
args = {}
|
|
314
|
+
) {
|
|
315
|
+
if (!channel || !category) {
|
|
316
|
+
return {
|
|
317
|
+
error: true,
|
|
318
|
+
message: !channel
|
|
319
|
+
? "Channel parameter is missing"
|
|
320
|
+
: "Category parameter is missing",
|
|
321
|
+
};
|
|
322
|
+
} else if (
|
|
323
|
+
![PreferenceOptions.OPT_IN, PreferenceOptions.OPT_OUT].includes(
|
|
324
|
+
preference
|
|
325
|
+
)
|
|
326
|
+
) {
|
|
327
|
+
return {
|
|
328
|
+
error: true,
|
|
329
|
+
message: "Preference parameter is invalid",
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (!this.data) {
|
|
334
|
+
return {
|
|
335
|
+
error: true,
|
|
336
|
+
message: "Call get_preferences method before performing action",
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
let category_data;
|
|
341
|
+
let selected_channel_data;
|
|
342
|
+
let data_updated = false;
|
|
343
|
+
|
|
344
|
+
// optimistic update in local store
|
|
345
|
+
for (let section of this.data.sections) {
|
|
346
|
+
let abort = false;
|
|
347
|
+
for (let subcategory of section.subcategories) {
|
|
348
|
+
if (subcategory.category === category) {
|
|
349
|
+
category_data = subcategory;
|
|
350
|
+
for (let channel_data of subcategory.channels) {
|
|
351
|
+
if (channel_data.channel === channel) {
|
|
352
|
+
selected_channel_data = channel_data;
|
|
353
|
+
if (channel_data.is_editable) {
|
|
354
|
+
if (channel_data.preference !== preference) {
|
|
355
|
+
channel_data.preference = preference;
|
|
356
|
+
if (preference === PreferenceOptions.OPT_IN) {
|
|
357
|
+
subcategory.preference = PreferenceOptions.OPT_IN;
|
|
358
|
+
}
|
|
359
|
+
data_updated = true;
|
|
360
|
+
abort = true;
|
|
361
|
+
break;
|
|
362
|
+
} else {
|
|
363
|
+
// console.log(`channel is already ${preference}`);
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
return {
|
|
367
|
+
error: true,
|
|
368
|
+
message: "Channel preference is not editable",
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (abort) break;
|
|
375
|
+
}
|
|
376
|
+
if (abort) break;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!category_data) {
|
|
380
|
+
return {
|
|
381
|
+
error: true,
|
|
382
|
+
message: "Category not found",
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (!selected_channel_data) {
|
|
387
|
+
return {
|
|
388
|
+
error: true,
|
|
389
|
+
message: "Category's Channel not found",
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (!data_updated) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const opt_out_channels = [];
|
|
398
|
+
category_data.channels.forEach((channel) => {
|
|
399
|
+
if (channel.preference === PreferenceOptions.OPT_OUT) {
|
|
400
|
+
opt_out_channels.push(channel.channel);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const request_payload = {
|
|
405
|
+
preference: category_data.preference,
|
|
406
|
+
opt_out_channels,
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
this._debounced_update_category_preferences(
|
|
410
|
+
category,
|
|
411
|
+
category,
|
|
412
|
+
request_payload,
|
|
413
|
+
category_data,
|
|
414
|
+
{ brand_id: args?.brand_id }
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
update_overall_channel_preference(channel = "", preference = "") {
|
|
419
|
+
if (
|
|
420
|
+
!channel ||
|
|
421
|
+
![
|
|
422
|
+
ChannelLevelPreferenceOptions.ALL,
|
|
423
|
+
ChannelLevelPreferenceOptions.REQUIRED,
|
|
424
|
+
].includes(preference)
|
|
425
|
+
) {
|
|
426
|
+
return {
|
|
427
|
+
error: true,
|
|
428
|
+
message: !channel
|
|
429
|
+
? "Channel parameter is missing"
|
|
430
|
+
: "Preference parameter is invalid",
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (!this.data) {
|
|
435
|
+
return {
|
|
436
|
+
error: true,
|
|
437
|
+
message: "Call get_preferences method before performing action",
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
let channel_data;
|
|
442
|
+
let data_updated = false;
|
|
443
|
+
const preference_restricted =
|
|
444
|
+
preference === ChannelLevelPreferenceOptions.REQUIRED;
|
|
445
|
+
|
|
446
|
+
for (let channel_item of this.data.channel_preferences) {
|
|
447
|
+
if (channel_item.channel === channel) {
|
|
448
|
+
channel_data = channel_item;
|
|
449
|
+
if (channel_item.is_restricted !== preference_restricted) {
|
|
450
|
+
channel_item.is_restricted = preference_restricted;
|
|
451
|
+
data_updated = true;
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (!channel_data) {
|
|
458
|
+
return {
|
|
459
|
+
error: true,
|
|
460
|
+
message: "Channel data not found",
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (!data_updated) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
this._debounced_update_channel_preferences(channel_data.channel, {
|
|
469
|
+
channel_preferences: [channel_data],
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export default Preferences;
|