@athoscommerce/snap-controller 1.0.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/dist/cjs/Abstract/AbstractController.d.ts +42 -0
  4. package/dist/cjs/Abstract/AbstractController.d.ts.map +1 -0
  5. package/dist/cjs/Abstract/AbstractController.js +305 -0
  6. package/dist/cjs/Autocomplete/AutocompleteController.d.ts +59 -0
  7. package/dist/cjs/Autocomplete/AutocompleteController.d.ts.map +1 -0
  8. package/dist/cjs/Autocomplete/AutocompleteController.js +1091 -0
  9. package/dist/cjs/Finder/FinderController.d.ts +15 -0
  10. package/dist/cjs/Finder/FinderController.d.ts.map +1 -0
  11. package/dist/cjs/Finder/FinderController.js +336 -0
  12. package/dist/cjs/Recommendation/RecommendationController.d.ts +27 -0
  13. package/dist/cjs/Recommendation/RecommendationController.d.ts.map +1 -0
  14. package/dist/cjs/Recommendation/RecommendationController.js +447 -0
  15. package/dist/cjs/Search/SearchController.d.ts +41 -0
  16. package/dist/cjs/Search/SearchController.d.ts.map +1 -0
  17. package/dist/cjs/Search/SearchController.js +993 -0
  18. package/dist/cjs/index.d.ts +7 -0
  19. package/dist/cjs/index.d.ts.map +1 -0
  20. package/dist/cjs/index.js +29 -0
  21. package/dist/cjs/types.d.ts +87 -0
  22. package/dist/cjs/types.d.ts.map +1 -0
  23. package/dist/cjs/types.js +10 -0
  24. package/dist/cjs/utils/getParams.d.ts +3 -0
  25. package/dist/cjs/utils/getParams.d.ts.map +1 -0
  26. package/dist/cjs/utils/getParams.js +70 -0
  27. package/dist/cjs/utils/isClickWithinBannerLink.d.ts +2 -0
  28. package/dist/cjs/utils/isClickWithinBannerLink.d.ts.map +1 -0
  29. package/dist/cjs/utils/isClickWithinBannerLink.js +21 -0
  30. package/dist/cjs/utils/isClickWithinProductLink.d.ts +5 -0
  31. package/dist/cjs/utils/isClickWithinProductLink.d.ts.map +1 -0
  32. package/dist/cjs/utils/isClickWithinProductLink.js +25 -0
  33. package/dist/esm/Abstract/AbstractController.d.ts +42 -0
  34. package/dist/esm/Abstract/AbstractController.d.ts.map +1 -0
  35. package/dist/esm/Abstract/AbstractController.js +208 -0
  36. package/dist/esm/Autocomplete/AutocompleteController.d.ts +59 -0
  37. package/dist/esm/Autocomplete/AutocompleteController.d.ts.map +1 -0
  38. package/dist/esm/Autocomplete/AutocompleteController.js +882 -0
  39. package/dist/esm/Finder/FinderController.d.ts +15 -0
  40. package/dist/esm/Finder/FinderController.d.ts.map +1 -0
  41. package/dist/esm/Finder/FinderController.js +218 -0
  42. package/dist/esm/Recommendation/RecommendationController.d.ts +27 -0
  43. package/dist/esm/Recommendation/RecommendationController.d.ts.map +1 -0
  44. package/dist/esm/Recommendation/RecommendationController.js +342 -0
  45. package/dist/esm/Search/SearchController.d.ts +41 -0
  46. package/dist/esm/Search/SearchController.d.ts.map +1 -0
  47. package/dist/esm/Search/SearchController.js +795 -0
  48. package/dist/esm/index.d.ts +7 -0
  49. package/dist/esm/index.d.ts.map +1 -0
  50. package/dist/esm/index.js +6 -0
  51. package/dist/esm/types.d.ts +87 -0
  52. package/dist/esm/types.d.ts.map +1 -0
  53. package/dist/esm/types.js +7 -0
  54. package/dist/esm/utils/getParams.d.ts +3 -0
  55. package/dist/esm/utils/getParams.d.ts.map +1 -0
  56. package/dist/esm/utils/getParams.js +67 -0
  57. package/dist/esm/utils/isClickWithinBannerLink.d.ts +2 -0
  58. package/dist/esm/utils/isClickWithinBannerLink.d.ts.map +1 -0
  59. package/dist/esm/utils/isClickWithinBannerLink.js +17 -0
  60. package/dist/esm/utils/isClickWithinProductLink.d.ts +5 -0
  61. package/dist/esm/utils/isClickWithinProductLink.d.ts.map +1 -0
  62. package/dist/esm/utils/isClickWithinProductLink.js +19 -0
  63. package/package.json +41 -0
@@ -0,0 +1,447 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ var __assign = (this && this.__assign) || function () {
18
+ __assign = Object.assign || function(t) {
19
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
20
+ s = arguments[i];
21
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
22
+ t[p] = s[p];
23
+ }
24
+ return t;
25
+ };
26
+ return __assign.apply(this, arguments);
27
+ };
28
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
29
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
30
+ return new (P || (P = Promise))(function (resolve, reject) {
31
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
33
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
34
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
35
+ });
36
+ };
37
+ var __generator = (this && this.__generator) || function (thisArg, body) {
38
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
39
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
40
+ function verb(n) { return function (v) { return step([n, v]); }; }
41
+ function step(op) {
42
+ if (f) throw new TypeError("Generator is already executing.");
43
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
44
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
45
+ if (y = 0, t) op = [op[0] & 2, t.value];
46
+ switch (op[0]) {
47
+ case 0: case 1: t = op; break;
48
+ case 4: _.label++; return { value: op[1], done: false };
49
+ case 5: _.label++; y = op[1]; op = [0]; continue;
50
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
51
+ default:
52
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
53
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
54
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
55
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
56
+ if (t[2]) _.ops.pop();
57
+ _.trys.pop(); continue;
58
+ }
59
+ op = body.call(thisArg, _);
60
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
61
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
62
+ }
63
+ };
64
+ var __importDefault = (this && this.__importDefault) || function (mod) {
65
+ return (mod && mod.__esModule) ? mod : { "default": mod };
66
+ };
67
+ Object.defineProperty(exports, "__esModule", { value: true });
68
+ exports.RecommendationController = void 0;
69
+ var deepmerge_1 = __importDefault(require("deepmerge"));
70
+ var snap_store_mobx_1 = require("@athoscommerce/snap-store-mobx");
71
+ var AbstractController_1 = require("../Abstract/AbstractController");
72
+ var types_1 = require("../types");
73
+ var isClickWithinProductLink_1 = require("../utils/isClickWithinProductLink");
74
+ var defaultConfig = {
75
+ id: 'recommend',
76
+ beacon: {
77
+ enabled: true,
78
+ },
79
+ tag: '',
80
+ batched: true,
81
+ realtime: false,
82
+ globals: {},
83
+ };
84
+ var RecommendationController = /** @class */ (function (_super) {
85
+ __extends(RecommendationController, _super);
86
+ function RecommendationController(config, _a, context) {
87
+ var client = _a.client, store = _a.store, urlManager = _a.urlManager, eventManager = _a.eventManager, profiler = _a.profiler, logger = _a.logger, tracker = _a.tracker;
88
+ var _b;
89
+ var _this = _super.call(this, config, { client: client, store: store, urlManager: urlManager, eventManager: eventManager, profiler: profiler, logger: logger, tracker: tracker }, context) || this;
90
+ _this.type = types_1.ControllerTypes.recommendation;
91
+ _this.events = {};
92
+ _this.track = {
93
+ product: {
94
+ clickThrough: function (e, result) {
95
+ var _a, _b, _c, _d, _e, _f, _g, _h;
96
+ if (!result) {
97
+ _this.log.warn('No result provided to track.product.clickThrough');
98
+ return;
99
+ }
100
+ var responseId = result.responseId;
101
+ if (!_this.events[responseId]) {
102
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
103
+ return;
104
+ }
105
+ if ((_b = (_a = _this.events[responseId]) === null || _a === void 0 ? void 0 : _a.product[result.id]) === null || _b === void 0 ? void 0 : _b.productClickThrough)
106
+ return;
107
+ var type = (['product', 'banner'].includes(result.type) ? result.type : 'product');
108
+ var beaconResult = __assign({ type: type, uid: result.id ? '' + result.id : '' }, (type === 'product'
109
+ ? {
110
+ parentId: ((_c = result.mappings.core) === null || _c === void 0 ? void 0 : _c.parentId) ? '' + ((_d = result.mappings.core) === null || _d === void 0 ? void 0 : _d.parentId) : '',
111
+ sku: ((_e = result.mappings.core) === null || _e === void 0 ? void 0 : _e.sku) ? '' + ((_f = result.mappings.core) === null || _f === void 0 ? void 0 : _f.sku) : undefined,
112
+ }
113
+ : {}));
114
+ var data = {
115
+ tag: _this.store.profile.tag,
116
+ responseId: responseId,
117
+ results: [beaconResult],
118
+ };
119
+ _this.eventManager.fire('track.product.clickThrough', { controller: _this, event: e, product: result, trackEvent: data });
120
+ ((_g = _this.config.beacon) === null || _g === void 0 ? void 0 : _g.enabled) && _this.tracker.events.recommendations.clickThrough({ data: data, siteId: (_h = _this.config.globals) === null || _h === void 0 ? void 0 : _h.siteId });
121
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
122
+ _this.events[responseId].product[result.id].productClickThrough = true;
123
+ },
124
+ click: function (e, result) {
125
+ var _a, _b, _c, _d, _e;
126
+ if (!result) {
127
+ _this.log.warn('No result provided to track.product.click');
128
+ return;
129
+ }
130
+ var responseId = result.responseId;
131
+ if (!_this.events[responseId]) {
132
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
133
+ return;
134
+ }
135
+ if (result.type === 'banner') {
136
+ if ((_b = (_a = _this.events[responseId]) === null || _a === void 0 ? void 0 : _a.product[result.id]) === null || _b === void 0 ? void 0 : _b.inlineBannerClickThrough) {
137
+ return;
138
+ }
139
+ _this.track.product.clickThrough(e, result);
140
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
141
+ _this.events[responseId].product[result.id].inlineBannerClickThrough = true;
142
+ setTimeout(function () {
143
+ _this.events[responseId].product[result.id].inlineBannerClickThrough = false;
144
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
145
+ }
146
+ else if ((0, isClickWithinProductLink_1.isClickWithinProductLink)(e, result)) {
147
+ if ((_e = (_d = (_c = _this.events) === null || _c === void 0 ? void 0 : _c[responseId]) === null || _d === void 0 ? void 0 : _d.product[result.id]) === null || _e === void 0 ? void 0 : _e.productClickThrough) {
148
+ return;
149
+ }
150
+ _this.track.product.clickThrough(e, result);
151
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
152
+ _this.events[responseId].product[result.id].productClickThrough = true;
153
+ setTimeout(function () {
154
+ _this.events[responseId].product[result.id].productClickThrough = false;
155
+ }, isClickWithinProductLink_1.CLICK_DUPLICATION_TIMEOUT);
156
+ }
157
+ },
158
+ impression: function (result) {
159
+ var _a, _b, _c, _d, _e, _f, _g, _h;
160
+ if (!result) {
161
+ _this.log.warn('No result provided to track.product.impression');
162
+ return;
163
+ }
164
+ var responseId = result.responseId;
165
+ if (!_this.events[responseId]) {
166
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
167
+ return;
168
+ }
169
+ else if ((_b = (_a = _this.events[responseId]) === null || _a === void 0 ? void 0 : _a.product[result.id]) === null || _b === void 0 ? void 0 : _b.impression) {
170
+ return;
171
+ }
172
+ var type = (['product', 'banner'].includes(result.type) ? result.type : 'product');
173
+ var item = __assign({ type: type, uid: result.id ? '' + result.id : '' }, (type === 'product'
174
+ ? {
175
+ parentId: ((_c = result.mappings.core) === null || _c === void 0 ? void 0 : _c.parentId) ? '' + ((_d = result.mappings.core) === null || _d === void 0 ? void 0 : _d.parentId) : '',
176
+ sku: ((_e = result.mappings.core) === null || _e === void 0 ? void 0 : _e.sku) ? '' + ((_f = result.mappings.core) === null || _f === void 0 ? void 0 : _f.sku) : undefined,
177
+ }
178
+ : {}));
179
+ var data = {
180
+ tag: _this.store.profile.tag,
181
+ responseId: responseId,
182
+ results: [item],
183
+ banners: [],
184
+ };
185
+ _this.eventManager.fire('track.product.impression', { controller: _this, product: result, trackEvent: data });
186
+ ((_g = _this.config.beacon) === null || _g === void 0 ? void 0 : _g.enabled) && _this.tracker.events.recommendations.impression({ data: data, siteId: (_h = _this.config.globals) === null || _h === void 0 ? void 0 : _h.siteId });
187
+ _this.events[responseId].product[result.id] = _this.events[responseId].product[result.id] || {};
188
+ _this.events[responseId].product[result.id].impression = true;
189
+ },
190
+ addToCart: function (result) {
191
+ var _a, _b, _c, _d, _e, _f;
192
+ if (!result) {
193
+ _this.log.warn('No result provided to track.product.addToCart');
194
+ return;
195
+ }
196
+ var responseId = result.responseId;
197
+ if (!_this.events[responseId]) {
198
+ _this.log.warn('No responseId found in controller, ensure correct controller is used');
199
+ return;
200
+ }
201
+ var product = {
202
+ parentId: ((_a = result.mappings.core) === null || _a === void 0 ? void 0 : _a.parentId) ? '' + ((_b = result.mappings.core) === null || _b === void 0 ? void 0 : _b.parentId) : '',
203
+ uid: result.id,
204
+ sku: (_c = result.mappings.core) === null || _c === void 0 ? void 0 : _c.sku,
205
+ qty: result.quantity || 1,
206
+ price: Number((_d = result.mappings.core) === null || _d === void 0 ? void 0 : _d.price),
207
+ };
208
+ var data = {
209
+ responseId: responseId,
210
+ tag: _this.store.profile.tag,
211
+ results: [product],
212
+ };
213
+ _this.eventManager.fire('track.product.addToCart', { controller: _this, product: result, trackEvent: data });
214
+ ((_e = _this.config.beacon) === null || _e === void 0 ? void 0 : _e.enabled) && _this.tracker.events.recommendations.addToCart({ data: data, siteId: (_f = _this.config.globals) === null || _f === void 0 ? void 0 : _f.siteId });
215
+ },
216
+ },
217
+ };
218
+ _this.search = function () { return __awaiter(_this, void 0, void 0, function () {
219
+ var params, err_1, searchProfile, _a, meta, profile, results, responseId, afterSearchProfile, err_2, data, afterStoreProfile, err_3, err_4;
220
+ var _b, _c;
221
+ return __generator(this, function (_d) {
222
+ switch (_d.label) {
223
+ case 0:
224
+ _d.trys.push([0, 16, 17, 18]);
225
+ if (!!this.initialized) return [3 /*break*/, 2];
226
+ return [4 /*yield*/, this.init()];
227
+ case 1:
228
+ _d.sent();
229
+ _d.label = 2;
230
+ case 2:
231
+ params = this.params;
232
+ this.store.loading = true;
233
+ _d.label = 3;
234
+ case 3:
235
+ _d.trys.push([3, 5, , 6]);
236
+ return [4 /*yield*/, this.eventManager.fire('beforeSearch', {
237
+ controller: this,
238
+ request: params,
239
+ })];
240
+ case 4:
241
+ _d.sent();
242
+ return [3 /*break*/, 6];
243
+ case 5:
244
+ err_1 = _d.sent();
245
+ if ((err_1 === null || err_1 === void 0 ? void 0 : err_1.message) == 'cancelled') {
246
+ this.log.warn("'beforeSearch' middleware cancelled");
247
+ return [2 /*return*/];
248
+ }
249
+ else {
250
+ this.log.error("error in 'beforeSearch' middleware");
251
+ throw err_1;
252
+ }
253
+ return [3 /*break*/, 6];
254
+ case 6:
255
+ searchProfile = this.profiler.create({ type: 'event', name: 'search', context: params }).start();
256
+ return [4 /*yield*/, this.client.recommend(params)];
257
+ case 7:
258
+ _a = _d.sent(), meta = _a.meta, profile = _a.profile, results = _a.results, responseId = _a.responseId;
259
+ searchProfile.stop();
260
+ this.log.profile(searchProfile);
261
+ this.events[responseId] = this.events[responseId] || { product: {} };
262
+ afterSearchProfile = this.profiler.create({ type: 'event', name: 'afterSearch', context: params }).start();
263
+ _d.label = 8;
264
+ case 8:
265
+ _d.trys.push([8, 10, , 11]);
266
+ return [4 /*yield*/, this.eventManager.fire('afterSearch', {
267
+ controller: this,
268
+ request: params,
269
+ response: { meta: meta, profile: profile, results: results },
270
+ })];
271
+ case 9:
272
+ _d.sent();
273
+ return [3 /*break*/, 11];
274
+ case 10:
275
+ err_2 = _d.sent();
276
+ if ((err_2 === null || err_2 === void 0 ? void 0 : err_2.message) == 'cancelled') {
277
+ this.log.warn("'afterSearch' middleware cancelled");
278
+ afterSearchProfile.stop();
279
+ return [2 /*return*/];
280
+ }
281
+ else {
282
+ this.log.error("error in 'afterSearch' middleware");
283
+ throw err_2;
284
+ }
285
+ return [3 /*break*/, 11];
286
+ case 11:
287
+ afterSearchProfile.stop();
288
+ this.log.profile(afterSearchProfile);
289
+ // update the store
290
+ this.store.update({
291
+ meta: meta,
292
+ profile: profile,
293
+ results: results,
294
+ responseId: responseId,
295
+ });
296
+ data = { responseId: responseId, tag: this.store.profile.tag };
297
+ ((_b = this.config.beacon) === null || _b === void 0 ? void 0 : _b.enabled) && this.tracker.events.recommendations.render({ data: data, siteId: (_c = this.config.globals) === null || _c === void 0 ? void 0 : _c.siteId });
298
+ afterStoreProfile = this.profiler.create({ type: 'event', name: 'afterStore', context: params }).start();
299
+ _d.label = 12;
300
+ case 12:
301
+ _d.trys.push([12, 14, , 15]);
302
+ return [4 /*yield*/, this.eventManager.fire('afterStore', {
303
+ controller: this,
304
+ request: params,
305
+ response: { meta: meta, profile: profile, results: results, responseId: responseId },
306
+ })];
307
+ case 13:
308
+ _d.sent();
309
+ return [3 /*break*/, 15];
310
+ case 14:
311
+ err_3 = _d.sent();
312
+ if ((err_3 === null || err_3 === void 0 ? void 0 : err_3.message) == 'cancelled') {
313
+ this.log.warn("'afterStore' middleware cancelled");
314
+ afterStoreProfile.stop();
315
+ return [2 /*return*/];
316
+ }
317
+ else {
318
+ this.log.error("error in 'afterStore' middleware");
319
+ throw err_3;
320
+ }
321
+ return [3 /*break*/, 15];
322
+ case 15:
323
+ afterStoreProfile.stop();
324
+ this.log.profile(afterStoreProfile);
325
+ return [3 /*break*/, 18];
326
+ case 16:
327
+ err_4 = _d.sent();
328
+ if (err_4) {
329
+ if (err_4.err && err_4.fetchDetails) {
330
+ switch (err_4.fetchDetails.status) {
331
+ case 429: {
332
+ this.store.error = {
333
+ code: 429,
334
+ type: snap_store_mobx_1.ErrorType.WARNING,
335
+ message: 'Too many requests try again later',
336
+ };
337
+ break;
338
+ }
339
+ case 500: {
340
+ this.store.error = {
341
+ code: 500,
342
+ type: snap_store_mobx_1.ErrorType.ERROR,
343
+ message: 'Invalid Search Request or Service Unavailable',
344
+ };
345
+ break;
346
+ }
347
+ default: {
348
+ this.store.error = {
349
+ type: snap_store_mobx_1.ErrorType.ERROR,
350
+ message: err_4.err.message,
351
+ };
352
+ break;
353
+ }
354
+ }
355
+ this.log.error(this.store.error);
356
+ this.handleError(err_4.err, err_4.fetchDetails);
357
+ }
358
+ else {
359
+ this.store.error = {
360
+ type: snap_store_mobx_1.ErrorType.ERROR,
361
+ message: "Something went wrong... - ".concat(err_4),
362
+ };
363
+ this.log.error(err_4);
364
+ this.handleError(err_4);
365
+ }
366
+ }
367
+ return [3 /*break*/, 18];
368
+ case 17:
369
+ this.store.loading = false;
370
+ return [7 /*endfinally*/];
371
+ case 18: return [2 /*return*/];
372
+ }
373
+ });
374
+ }); };
375
+ _this.addToCart = function (_products) { return __awaiter(_this, void 0, void 0, function () {
376
+ var products;
377
+ var _this = this;
378
+ return __generator(this, function (_a) {
379
+ products = typeof (_products === null || _products === void 0 ? void 0 : _products.slice) == 'function' ? _products.slice() : [_products];
380
+ if (!_products || products.length === 0) {
381
+ this.log.warn('No products provided to recommendation controller.addToCart');
382
+ return [2 /*return*/];
383
+ }
384
+ products.forEach(function (product) {
385
+ _this.track.product.addToCart(product);
386
+ });
387
+ if (products.length > 0) {
388
+ this.eventManager.fire('addToCart', { controller: this, products: products });
389
+ }
390
+ return [2 /*return*/];
391
+ });
392
+ }); };
393
+ if (!config.tag) {
394
+ throw new Error("Invalid config passed to RecommendationController. The \"tag\" attribute is required.");
395
+ }
396
+ // attach to bfCache restore event and re-run search on the controller
397
+ // enabled by default
398
+ if (((_b = config.settings) === null || _b === void 0 ? void 0 : _b.searchOnPageShow) !== false) {
399
+ window.addEventListener('pageshow', function (e) {
400
+ if (e.persisted && !_this.store.error && _this.store.loaded && !_this.store.loading) {
401
+ _this.search();
402
+ }
403
+ });
404
+ }
405
+ // deep merge config with defaults
406
+ _this.config = (0, deepmerge_1.default)(defaultConfig, _this.config);
407
+ _this.store.setConfig(_this.config);
408
+ // add 'afterStore' middleware
409
+ // this.eventManager.on('afterStore', async (recommend: AfterStoreObj, next: Next): Promise<void | boolean> => {
410
+ // await next();
411
+ // // attach tracking events to cart store
412
+ // this.store.cart?.on('addItems', ({ items }: { items: Product[] }) => {
413
+ // // add to bundle
414
+ // });
415
+ // this.store.cart?.on('removeItems', ({ items }: { items: Product[] }) => {
416
+ // // remove from bundle
417
+ // });
418
+ // });
419
+ // attach config plugins and event middleware
420
+ _this.use(_this.config);
421
+ return _this;
422
+ }
423
+ Object.defineProperty(RecommendationController.prototype, "params", {
424
+ get: function () {
425
+ var params = __assign({ tag: this.config.tag, batched: this.config.batched, branch: this.config.branch || 'production', batchId: this.config.batchId }, this.config.globals);
426
+ var shopperId = this.tracker.getContext().shopperId;
427
+ if (shopperId) {
428
+ params.shopper = shopperId;
429
+ }
430
+ if (!params.siteId || params.siteId == this.tracker.getGlobals().siteId) {
431
+ var cart = this.tracker.cookies.cart.get();
432
+ var lastViewed = this.tracker.cookies.viewed.get();
433
+ if (cart === null || cart === void 0 ? void 0 : cart.length) {
434
+ params.cart = cart;
435
+ }
436
+ if (lastViewed === null || lastViewed === void 0 ? void 0 : lastViewed.length) {
437
+ params.lastViewed = lastViewed;
438
+ }
439
+ }
440
+ return params;
441
+ },
442
+ enumerable: false,
443
+ configurable: true
444
+ });
445
+ return RecommendationController;
446
+ }(AbstractController_1.AbstractController));
447
+ exports.RecommendationController = RecommendationController;
@@ -0,0 +1,41 @@
1
+ import { AbstractController } from '../Abstract/AbstractController';
2
+ import { StorageStore, MerchandisingContentBanner } from '@athoscommerce/snap-store-mobx';
3
+ import { ControllerTypes } from '../types';
4
+ import type { Product, Banner, SearchStore } from '@athoscommerce/snap-store-mobx';
5
+ import type { SearchControllerConfig, ControllerServices, ContextVariables } from '../types';
6
+ import { type SearchRequestModel } from '@athoscommerce/snapi-types';
7
+ type SearchTrackMethods = {
8
+ banner: {
9
+ click: (e: MouseEvent, merchandisingBanner: MerchandisingContentBanner) => void;
10
+ clickThrough: (e: MouseEvent, merchandisingBanner: MerchandisingContentBanner) => void;
11
+ impression: (merchandisingBanner: MerchandisingContentBanner) => void;
12
+ };
13
+ product: {
14
+ clickThrough: (e: MouseEvent, result: Product | Banner) => void;
15
+ click: (e: MouseEvent, result: Product | Banner) => void;
16
+ impression: (result: Product | Banner) => void;
17
+ addToCart: (results: Product) => void;
18
+ };
19
+ redirect: ({ redirectURL, responseId }: {
20
+ redirectURL: string;
21
+ responseId: string;
22
+ }) => void;
23
+ };
24
+ export declare class SearchController extends AbstractController {
25
+ type: ControllerTypes;
26
+ store: SearchStore;
27
+ config: SearchControllerConfig;
28
+ storage: StorageStore;
29
+ private previousResults;
30
+ private page;
31
+ private events;
32
+ constructor(config: SearchControllerConfig, { client, store, urlManager, eventManager, profiler, logger, tracker }: ControllerServices, context?: ContextVariables);
33
+ track: SearchTrackMethods;
34
+ get params(): SearchRequestModel;
35
+ search: () => Promise<void>;
36
+ addToCart: (_products: Product[] | Product) => Promise<void>;
37
+ }
38
+ export declare function getStorableRequestParams(request: SearchRequestModel): SearchRequestModel;
39
+ export declare function generateHrefSelector(element: HTMLElement, href: string, levels?: number): string | undefined;
40
+ export {};
41
+ //# sourceMappingURL=SearchController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchController.d.ts","sourceRoot":"","sources":["../../../src/Search/SearchController.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAa,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAErG,OAAO,EAAE,eAAe,EAAuB,MAAM,UAAU,CAAC;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAiC,MAAM,gCAAgC,CAAC;AAClH,OAAO,KAAK,EACX,sBAAsB,EAGtB,kBAAkB,EAClB,gBAAgB,EAIhB,MAAM,UAAU,CAAC;AAElB,OAAO,EACN,KAAK,kBAAkB,EAYvB,MAAM,4BAA4B,CAAC;AAyCpC,KAAK,kBAAkB,GAAG;IACzB,MAAM,EAAE;QACP,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,0BAA0B,KAAK,IAAI,CAAC;QAChF,YAAY,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,0BAA0B,KAAK,IAAI,CAAC;QACvF,UAAU,EAAE,CAAC,mBAAmB,EAAE,0BAA0B,KAAK,IAAI,CAAC;KACtE,CAAC;IACF,OAAO,EAAE;QACR,YAAY,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;QACzD,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;QAC/C,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;KACtC,CAAC;IACF,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7F,CAAC;AAEF,qBAAa,gBAAiB,SAAQ,kBAAkB;IAChD,IAAI,kBAA0B;IAC7B,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,sBAAsB,CAAC;IACvC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,IAAI,CAEV;IACF,OAAO,CAAC,MAAM,CAiBP;gBAGN,MAAM,EAAE,sBAAsB,EAC9B,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,EAC1F,OAAO,CAAC,EAAE,gBAAgB;IA2Q3B,KAAK,EAAE,kBAAkB,CA0PvB;IAEF,IAAI,MAAM,IAAI,kBAAkB,CA8C/B;IAED,MAAM,QAAa,OAAO,CAAC,IAAI,CAAC,CAiO9B;IAEF,SAAS,cAAqB,OAAO,EAAE,GAAG,OAAO,KAAG,OAAO,CAAC,IAAI,CAAC,CAY/D;CACF;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,kBAAkB,GAAG,kBAAkB,CAiBxF;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,GAAG,SAAS,CAuCvG"}