@phystack/products 4.3.40-dev

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 (44) hide show
  1. package/CHANGELOG.md +2736 -0
  2. package/dist/api.d.ts +11 -0
  3. package/dist/api.js +49 -0
  4. package/dist/helpers.d.ts +2 -0
  5. package/dist/helpers.js +11 -0
  6. package/dist/index.d.ts +7 -0
  7. package/dist/index.js +29 -0
  8. package/dist/index.test.d.ts +1 -0
  9. package/dist/index.test.js +1423 -0
  10. package/dist/services/grid-product-service-admin.d.ts +23 -0
  11. package/dist/services/grid-product-service-admin.js +120 -0
  12. package/dist/services/grid-product-service-client.d.ts +80 -0
  13. package/dist/services/grid-product-service-client.js +633 -0
  14. package/dist/services/grid-product-service-interface.d.ts +47 -0
  15. package/dist/services/grid-product-service-interface.js +2 -0
  16. package/dist/services/http-service.d.ts +14 -0
  17. package/dist/services/http-service.js +44 -0
  18. package/dist/types/grid-product.d.ts +458 -0
  19. package/dist/types/grid-product.js +38 -0
  20. package/dist/types/iso-currency-codes.d.ts +182 -0
  21. package/dist/types/iso-currency-codes.js +186 -0
  22. package/dist/types/iso-language-ids.d.ts +170 -0
  23. package/dist/types/iso-language-ids.js +174 -0
  24. package/dist/types/parameters.d.ts +242 -0
  25. package/dist/types/parameters.js +99 -0
  26. package/dist/utils.d.ts +27 -0
  27. package/dist/utils.js +187 -0
  28. package/jest.config.js +10 -0
  29. package/jest.setup.js +1 -0
  30. package/package.json +31 -0
  31. package/src/api.ts +47 -0
  32. package/src/helpers.ts +7 -0
  33. package/src/index.test.ts +1526 -0
  34. package/src/index.ts +8 -0
  35. package/src/services/grid-product-service-admin.ts +123 -0
  36. package/src/services/grid-product-service-client.ts +995 -0
  37. package/src/services/grid-product-service-interface.ts +105 -0
  38. package/src/services/http-service.ts +50 -0
  39. package/src/types/grid-product.ts +548 -0
  40. package/src/types/iso-currency-codes.ts +182 -0
  41. package/src/types/iso-language-ids.ts +170 -0
  42. package/src/types/parameters.ts +231 -0
  43. package/src/utils.ts +325 -0
  44. package/tsconfig.json +20 -0
@@ -0,0 +1,995 @@
1
+ import HttpService from './http-service';
2
+ import {
3
+ ProductDetailsByCodeQueryParameters,
4
+ ProductDetailsQueryParameters,
5
+ ProductFiltersQueryParameters,
6
+ ProductGroupStoresInventoryParam,
7
+ ProductGroupStoresInventoryResponse,
8
+ ProductQueryParameters,
9
+ ProductRecommendationsQueryParameters,
10
+ ProductTypesListQueryParameters,
11
+ ProductTypesListWithSpaceProductsQueryParameters,
12
+ RequestTypeEnum,
13
+ SearchQueryParameters,
14
+ } from '../types/parameters';
15
+ import {
16
+ BaseSelectorProps,
17
+ DataResidencyEnum,
18
+ FilterByGroup,
19
+ FilterByLanguage,
20
+ GetCartPromotionsParams,
21
+ GetCartPromotionsResponse,
22
+ GetVariantActivePriceParams,
23
+ GetVariantActivePriceResponse,
24
+ GridProduct,
25
+ GridProductSelectors,
26
+ InventoryItem,
27
+ PriceListTypeEnum,
28
+ ProductBrand,
29
+ ProductDescription,
30
+ ProductName,
31
+ ProductRecommendationLibraryResponse,
32
+ ProductRecommendationResponse,
33
+ ProductShortDescription,
34
+ ProductType,
35
+ SelectablePartialProduct,
36
+ SingleLocalizedResult,
37
+ SortOptionsResponse,
38
+ VariantInfo,
39
+ VariantInventory,
40
+ } from '../types/grid-product';
41
+ import { setApiEndpoint } from '../api';
42
+ import { IsoLanguageIds } from '../types/iso-language-ids';
43
+ import GridProductServiceInterface from './grid-product-service-interface';
44
+
45
+
46
+ interface GetProductListResponse {
47
+ list: Partial<GridProduct>[];
48
+ attributeFilters: FilterByLanguage;
49
+ }
50
+
51
+ interface GetProductListLibraryResponse extends GetProductListResponse {
52
+ list: SelectablePartialProduct[];
53
+ }
54
+
55
+ type Options = {
56
+ tenantId: string;
57
+ environment: string;
58
+ dataResidency: DataResidencyEnum;
59
+ locale: IsoLanguageIds;
60
+ fallbackLocale?: IsoLanguageIds;
61
+ };
62
+
63
+ type JSONValue = string | number | boolean | null | JSONObject | JSONArray;
64
+
65
+ interface JSONObject {
66
+ [key: string]: JSONValue;
67
+ }
68
+
69
+ type JSONArray = JSONValue[];
70
+
71
+ export class GridProductServiceClient implements GridProductServiceInterface {
72
+ readonly httpService: HttpService;
73
+
74
+ locale: IsoLanguageIds;
75
+
76
+ fallbackLocale?: IsoLanguageIds;
77
+
78
+ apiEndpoint: string;
79
+
80
+ tenantId: string;
81
+
82
+ constructor({ tenantId, environment, dataResidency, locale, fallbackLocale }: Options) {
83
+ if (!tenantId) {
84
+ throw new Error('Error: tenantId is required');
85
+ }
86
+
87
+ if (!environment) {
88
+ throw new Error('Error: environment is required');
89
+ }
90
+
91
+ const apiEndpoint: string = setApiEndpoint(dataResidency);
92
+
93
+ this.httpService = new HttpService({
94
+ baseUrl: `${apiEndpoint}/tenants/${tenantId}/${environment}`,
95
+ });
96
+
97
+ this.apiEndpoint = apiEndpoint;
98
+
99
+ this.tenantId = tenantId;
100
+
101
+ this.locale = locale;
102
+
103
+ this.fallbackLocale = fallbackLocale;
104
+ }
105
+
106
+ getLocalizedValue = <T extends { isoLanguageId?: IsoLanguageIds | '*' }>(
107
+ list: T[],
108
+ locale: IsoLanguageIds | '*',
109
+ ): T | undefined => {
110
+ const fallbackLocale = this.fallbackLocale;
111
+
112
+ const filteredList = list.filter((item) => item.isoLanguageId === locale);
113
+
114
+ if (filteredList.length === 0 && fallbackLocale) {
115
+ const newFilteredList = list.filter(
116
+ (item) => item.isoLanguageId === fallbackLocale,
117
+ );
118
+
119
+ return newFilteredList[0];
120
+ }
121
+
122
+ return filteredList[0];
123
+ };
124
+
125
+ getLocalizedList = <T extends { isoLanguageId?: IsoLanguageIds | '*' }>(
126
+ list: T[],
127
+ locale: IsoLanguageIds | '*',
128
+ ): T[] => {
129
+ if (locale === '*') {
130
+ return list;
131
+ }
132
+
133
+ const filteredList = list.filter((item) => {
134
+ if (!item.isoLanguageId) {
135
+ return true;
136
+ }
137
+
138
+ return item.isoLanguageId === locale;
139
+ });
140
+
141
+ const fallbackLocale = this.fallbackLocale;
142
+
143
+ if (filteredList.length === 0 && fallbackLocale) {
144
+ const newFilteredList = list.filter(
145
+ (item) => item.isoLanguageId === fallbackLocale,
146
+ );
147
+
148
+ return newFilteredList;
149
+ }
150
+
151
+ return filteredList;
152
+ };
153
+
154
+ getFilteredList = <T>(list: T[], filterFn: ((item: T) => boolean) | undefined) => {
155
+ if (!filterFn) {
156
+ return list;
157
+ }
158
+
159
+ return list.filter(filterFn);
160
+ };
161
+
162
+ buildSelectableProduct = (product: Partial<GridProduct>): SelectablePartialProduct => {
163
+ const defaultLocale = this.locale;
164
+
165
+ const getShortDescription: GridProductSelectors['getShortDescription'] = <
166
+ T extends BaseSelectorProps,
167
+ >(
168
+ input?: T,
169
+ ) => {
170
+ const locale = input?.locale ?? defaultLocale;
171
+
172
+ const list = product.productShortDescription ?? [];
173
+
174
+ const localizedValue = this.getLocalizedValue(list, locale);
175
+
176
+ const value = localizedValue?.productShortDescription ?? '';
177
+
178
+ return input?.locale === '*'
179
+ ? <SingleLocalizedResult<T, ProductShortDescription, string>>list
180
+ : <SingleLocalizedResult<T, ProductShortDescription, string>>value;
181
+ };
182
+
183
+ const getLabel: GridProductSelectors['getLabel'] = (input) => {
184
+ const locale = input?.locale ?? defaultLocale;
185
+
186
+ const filterFn = input?.filter;
187
+
188
+ const list = product.productLabel ?? [];
189
+
190
+ const newList = this.getFilteredList(this.getLocalizedList(list, locale), filterFn);
191
+
192
+ return newList.map((item) => item.productLabel);
193
+ };
194
+
195
+ const getLabelBySpace: GridProductSelectors['getLabelBySpace'] = (input) =>
196
+ getLabel({
197
+ ...input,
198
+ filter: (item) => item.spaceId === input.spaceId,
199
+ });
200
+
201
+ const getPriceList: GridProductSelectors['getPriceList'] = (input?) => {
202
+ const filterFn = input?.filter;
203
+
204
+ const list = product.productPriceList ?? [];
205
+
206
+ const filteredList = this.getFilteredList(list, filterFn);
207
+
208
+ return filteredList;
209
+ };
210
+
211
+ const getStandardPrice: GridProductSelectors['getStandardPrice'] = ({ spaceId }) => {
212
+ const priceList = getPriceList({
213
+ filter: (item) =>
214
+ item.spaceId === spaceId && item.priceListType === PriceListTypeEnum.Standard,
215
+ });
216
+
217
+ const firstItem = priceList[0];
218
+
219
+ if (!firstItem) {
220
+ return undefined;
221
+ }
222
+
223
+ return { amount: firstItem.listPrice, currencyCode: firstItem.isoCurrencyCode };
224
+ };
225
+
226
+ const getPromotionalPrice: GridProductSelectors['getStandardPrice'] = ({
227
+ spaceId,
228
+ }) => {
229
+ const priceList = getPriceList({
230
+ filter: (item) =>
231
+ item.spaceId === spaceId &&
232
+ item.priceListType === PriceListTypeEnum.Promotional,
233
+ });
234
+
235
+ const firstItem = priceList[0];
236
+
237
+ if (!firstItem) {
238
+ return undefined;
239
+ }
240
+
241
+ return { amount: firstItem.listPrice, currencyCode: firstItem.isoCurrencyCode };
242
+ };
243
+
244
+ const getName: GridProductSelectors['getName'] = <T extends BaseSelectorProps>(
245
+ input?: T,
246
+ ) => {
247
+ const locale = input?.locale ?? defaultLocale;
248
+
249
+ const list = product.productName ?? [];
250
+
251
+ const localizedValue = this.getLocalizedValue(list, locale);
252
+
253
+ const value = localizedValue?.productName ?? '';
254
+
255
+ return input?.locale === '*'
256
+ ? <SingleLocalizedResult<T, ProductName, string>>list
257
+ : <SingleLocalizedResult<T, ProductName, string>>value;
258
+ };
259
+
260
+ const getDescription: GridProductSelectors['getDescription'] = <
261
+ T extends BaseSelectorProps,
262
+ >(
263
+ input?: T,
264
+ ) => {
265
+ const locale = input?.locale ?? defaultLocale;
266
+
267
+ const list = product.productDescription ?? [];
268
+
269
+ const localizedValue = this.getLocalizedValue(list, locale);
270
+
271
+ const value = localizedValue?.productDescription ?? '';
272
+
273
+ return input?.locale === '*'
274
+ ? <SingleLocalizedResult<T, ProductDescription, string>>list
275
+ : <SingleLocalizedResult<T, ProductDescription, string>>value;
276
+ };
277
+
278
+ const getBrandName: GridProductSelectors['getBrandName'] = <
279
+ T extends BaseSelectorProps,
280
+ >(
281
+ input?: T,
282
+ ) => {
283
+ const locale = input?.locale ?? defaultLocale;
284
+
285
+ const list = product.brand ?? [];
286
+
287
+ const localizedValue = this.getLocalizedValue(list, locale);
288
+
289
+ const value = localizedValue?.brandName ?? '';
290
+
291
+ return input?.locale === '*'
292
+ ? <SingleLocalizedResult<T, ProductBrand, string>>list
293
+ : <SingleLocalizedResult<T, ProductBrand, string>>value;
294
+ };
295
+
296
+ const getItemQuantity: GridProductSelectors['getItemQuantity'] = (input) => {
297
+ const filterFn = input?.filter;
298
+
299
+ const list = product.productItemQuantity ?? [];
300
+
301
+ const filteredList = this.getFilteredList(list, filterFn);
302
+
303
+ return filteredList;
304
+ };
305
+
306
+ const getVariantQuantity: GridProductSelectors['getVariantQuantity'] = ({
307
+ variantId,
308
+ spaceId,
309
+ }) => {
310
+ const filteredList = getItemQuantity({
311
+ filter: (item) => {
312
+ if (!spaceId) {
313
+ return item.productId === variantId;
314
+ }
315
+
316
+ return item.productId === variantId && item.spaceId === spaceId;
317
+ },
318
+ });
319
+
320
+ const sum = filteredList.reduce(
321
+ (accumulator, item) => accumulator + item.productItemQuantity,
322
+ 0,
323
+ );
324
+
325
+ return sum;
326
+ };
327
+
328
+ const getCatalogPageLocationProduct: GridProductSelectors['getCatalogPageLocationProduct'] =
329
+ (input) => {
330
+ const filterFn = input?.filter;
331
+
332
+ const list = product.catalogPageLocationProduct ?? [];
333
+
334
+ const filteredList = this.getFilteredList(list, filterFn);
335
+
336
+ return filteredList;
337
+ };
338
+
339
+ const getImages: GridProductSelectors['getImages'] = () => {
340
+ const list = getCatalogPageLocationProduct();
341
+
342
+ const result = list.map((item) => item.catalogPageLocationProduct);
343
+
344
+ return result;
345
+ };
346
+
347
+ const getImage: GridProductSelectors['getImage'] = () => {
348
+ const list = getCatalogPageLocationProduct();
349
+
350
+ const images = list.map((item) => item.catalogPageLocationProduct);
351
+
352
+ const result = images[0] ?? '';
353
+
354
+ return result;
355
+ };
356
+
357
+ const getFeature: GridProductSelectors['getFeature'] = (input) => {
358
+ const locale = input?.locale ?? defaultLocale;
359
+
360
+ const filterFn = input?.filter;
361
+
362
+ const list = product.productFeature ?? [];
363
+
364
+ const filteredList = this.getFilteredList(
365
+ this.getLocalizedList(list, locale),
366
+ filterFn,
367
+ );
368
+
369
+ return filteredList;
370
+ };
371
+
372
+ const getVariantFeature: GridProductSelectors['getVariantFeature'] = (input) =>
373
+ getFeature({
374
+ ...input,
375
+ filter: (item) => item.productId === input.productId,
376
+ });
377
+
378
+ const getVariants: GridProductSelectors['getVariants'] = (input) => {
379
+ const filterFn = input?.filter;
380
+
381
+ const list = product.variants ?? [];
382
+
383
+ const filteredList = this.getFilteredList(list, filterFn);
384
+
385
+ return filteredList;
386
+ };
387
+
388
+ const getFirstVariant: GridProductSelectors['getFirstVariant'] = () => {
389
+ const variants = getVariants();
390
+
391
+ const result = variants[0];
392
+
393
+ return result;
394
+ };
395
+
396
+ const getVariantsByProductId: GridProductSelectors['getVariantsByProductId'] = ({
397
+ productId,
398
+ }) => getVariants({ filter: (item) => item.productId === productId });
399
+
400
+ const getVariantImages: GridProductSelectors['getVariantImages'] = ({
401
+ variantId,
402
+ }) => {
403
+ const filteredList = getCatalogPageLocationProduct({
404
+ filter: (item) => item.productId === variantId,
405
+ });
406
+
407
+ const result = filteredList.map((item) => item.catalogPageLocationProduct);
408
+
409
+ return result;
410
+ };
411
+
412
+ const getVariantStandardPrice: GridProductSelectors['getVariantStandardPrice'] = ({
413
+ variantId,
414
+ spaceId,
415
+ }) => {
416
+ const priceList = getPriceList({
417
+ filter: (item) =>
418
+ item.productId === variantId &&
419
+ item.spaceId === spaceId &&
420
+ item.priceListType === PriceListTypeEnum.Standard,
421
+ });
422
+
423
+ const firstItem = priceList[0];
424
+
425
+ if (!firstItem) {
426
+ return undefined;
427
+ }
428
+
429
+ return { amount: firstItem.listPrice, currencyCode: firstItem.isoCurrencyCode };
430
+ };
431
+
432
+ const getVariantPromotionalPrice: GridProductSelectors['getVariantPromotionalPrice'] =
433
+ ({ variantId, spaceId }) => {
434
+ const priceList = getPriceList({
435
+ filter: (item) =>
436
+ item.productId === variantId &&
437
+ item.spaceId === spaceId &&
438
+ item.priceListType === PriceListTypeEnum.Promotional,
439
+ });
440
+
441
+ const firstItem = priceList[0];
442
+
443
+ if (!firstItem) {
444
+ return undefined;
445
+ }
446
+
447
+ return { amount: firstItem.listPrice, currencyCode: firstItem.isoCurrencyCode };
448
+ };
449
+
450
+ const selectableProduct: SelectablePartialProduct = {
451
+ ...product,
452
+ getShortDescription,
453
+ getLabel,
454
+ getLabelBySpace,
455
+ getPriceList,
456
+ getStandardPrice,
457
+ getPromotionalPrice,
458
+ getName,
459
+ getDescription,
460
+ getBrandName,
461
+ getItemQuantity,
462
+ getCatalogPageLocationProduct,
463
+ getImages,
464
+ getImage,
465
+ getFeature,
466
+ getVariantFeature,
467
+ getVariants,
468
+ getFirstVariant,
469
+ getVariantsByProductId,
470
+ getVariantImages,
471
+ getVariantStandardPrice,
472
+ getVariantPromotionalPrice,
473
+ getVariantQuantity,
474
+ };
475
+
476
+ return selectableProduct;
477
+ };
478
+
479
+ getProductById = async (
480
+ id: string,
481
+ params: ProductDetailsQueryParameters,
482
+ ): Promise<SelectablePartialProduct> => {
483
+ try {
484
+ const result = await this.httpService.get(`/products/${id}`, {
485
+ params,
486
+ });
487
+
488
+ return this.buildSelectableProduct(result.data);
489
+ } catch (err) {
490
+ // @ts-ignore
491
+ throw new Error(err.response.data.message ?? err.message);
492
+ }
493
+ };
494
+
495
+ getProductByBarcode = async (
496
+ code: string,
497
+ params: ProductDetailsByCodeQueryParameters,
498
+ ): Promise<{
499
+ productDetails: SelectablePartialProduct;
500
+ productId: string;
501
+ }> => {
502
+ try {
503
+ const result = await this.httpService.get<{
504
+ data: { productDetails: Partial<GridProduct>; productId: string };
505
+ }>(`/products-barcode/${code}`, {
506
+ params,
507
+ });
508
+
509
+ return {
510
+ productDetails: this.buildSelectableProduct(result.data.productDetails),
511
+ productId: result.data.productId,
512
+ };
513
+ } catch (err) {
514
+ // @ts-ignore
515
+ throw new Error(err.response.data.message ?? err.message);
516
+ }
517
+ };
518
+
519
+ getProductList = async (
520
+ params?: ProductQueryParameters,
521
+ ): Promise<GetProductListLibraryResponse> => {
522
+ try {
523
+ const buildParams = (params?: ProductQueryParameters): Record<string, string> => {
524
+ const stringParams: Record<string, string> = {};
525
+
526
+ if (params) {
527
+ Object.keys(params).forEach((key) => {
528
+ stringParams[key] = params[
529
+ key as keyof ProductQueryParameters
530
+ ]?.toString() as string;
531
+ });
532
+ }
533
+
534
+ return stringParams;
535
+ };
536
+
537
+ const getRequestLength = (path: string, params: Record<string, string>): number => {
538
+ return (
539
+ path.length +
540
+ Object.entries(params).reduce((acc, [key, value]) => {
541
+ return (
542
+ acc + encodeURIComponent(key).length + encodeURIComponent(value).length + 2
543
+ );
544
+ }, 0)
545
+ );
546
+ };
547
+
548
+ const allowedGetRequestLength = 2048; // Replace with the allowed GET API request length
549
+ const requestPath = '/products';
550
+ const requestParams = buildParams(params);
551
+
552
+ const requestType =
553
+ getRequestLength(requestPath, requestParams) < allowedGetRequestLength
554
+ ? RequestTypeEnum.GET
555
+ : RequestTypeEnum.POST;
556
+
557
+ const result =
558
+ requestType === RequestTypeEnum.POST
559
+ ? await this.httpService.post<{ data: GetProductListResponse }>(requestPath, {
560
+ ...params,
561
+ })
562
+ : await this.httpService.get<{ data: GetProductListResponse }>(requestPath, {
563
+ params: requestParams,
564
+ });
565
+
566
+ const response = {
567
+ ...result.data,
568
+ list: result.data.list.map(this.buildSelectableProduct),
569
+ };
570
+
571
+ return response;
572
+ } catch (err) {
573
+ // @ts-ignore
574
+ throw new Error(err.response.data.message ?? err.message);
575
+ }
576
+ };
577
+
578
+ // TODO: Remove
579
+ // Temporary - for testing purposes only on v2 product list connected to cosmos
580
+ getProductListV2 = async (
581
+ params?: ProductQueryParameters,
582
+ ): Promise<GetProductListLibraryResponse> => {
583
+ try {
584
+ const buildParams = (params?: ProductQueryParameters): Record<string, string> => {
585
+ const stringParams: Record<string, string> = {};
586
+
587
+ if (params) {
588
+ Object.keys(params).forEach((key) => {
589
+ stringParams[key] = params[
590
+ key as keyof ProductQueryParameters
591
+ ]?.toString() as string;
592
+ });
593
+ }
594
+
595
+ return stringParams;
596
+ };
597
+
598
+ const getRequestLength = (path: string, params: Record<string, string>): number => {
599
+ return (
600
+ path.length +
601
+ Object.entries(params).reduce((acc, [key, value]) => {
602
+ return (
603
+ acc + encodeURIComponent(key).length + encodeURIComponent(value).length + 2
604
+ );
605
+ }, 0)
606
+ );
607
+ };
608
+
609
+ const allowedGetRequestLength = 2048; // Replace with the allowed GET API request length
610
+ const requestPath = '/products-v2';
611
+ const requestParams = buildParams(params);
612
+
613
+ const requestType =
614
+ getRequestLength(requestPath, requestParams) < allowedGetRequestLength
615
+ ? RequestTypeEnum.GET
616
+ : RequestTypeEnum.POST;
617
+
618
+ const result =
619
+ requestType === RequestTypeEnum.POST
620
+ ? await this.httpService.post<{ data: GetProductListResponse }>(requestPath, {
621
+ ...params,
622
+ })
623
+ : await this.httpService.get<{ data: GetProductListResponse }>(requestPath, {
624
+ params: requestParams,
625
+ });
626
+
627
+ const response = {
628
+ ...result.data,
629
+ list: result.data.list.map(this.buildSelectableProduct),
630
+ };
631
+
632
+ return response;
633
+ } catch (err) {
634
+ // @ts-ignore
635
+ throw new Error(err.response.data.message ?? err.message);
636
+ }
637
+ };
638
+
639
+ search = async (
640
+ params: SearchQueryParameters,
641
+ ): Promise<{
642
+ products: SelectablePartialProduct[];
643
+ productTypes: Array<ProductType>;
644
+ }> => {
645
+ try {
646
+ const result = await this.httpService.get<{
647
+ data: {
648
+ products: Array<Partial<GridProduct>>;
649
+ productTypes: Array<ProductType>;
650
+ };
651
+ }>('/search', {
652
+ params,
653
+ });
654
+
655
+ const response = {
656
+ ...result.data,
657
+ products: result.data.products.map(this.buildSelectableProduct),
658
+ };
659
+
660
+ return response;
661
+ } catch (err) {
662
+ // @ts-ignore
663
+ throw new Error(err.response.data.message ?? err.message);
664
+ }
665
+ };
666
+
667
+ getProductTypesList = async (
668
+ params?: ProductTypesListQueryParameters,
669
+ ): Promise<ProductType[]> => {
670
+ try {
671
+ const result = await this.httpService.get('/product-types', {
672
+ params: {
673
+ ...params,
674
+ ids: params?.ids?.join(',') ?? '',
675
+ },
676
+ });
677
+ return result.data;
678
+ } catch (err) {
679
+ // @ts-ignore
680
+ throw new Error(err.response.data.message ?? err.message);
681
+ }
682
+ };
683
+
684
+ getProductTypesListWithSpaceProducts = async (
685
+ params: ProductTypesListWithSpaceProductsQueryParameters,
686
+ ): Promise<ProductType[]> => {
687
+ try {
688
+ const result = await this.httpService.get('/product-types-with-space-products', {
689
+ params: {
690
+ spaceIds: params.spaceIds.join(','),
691
+ },
692
+ });
693
+ return result.data;
694
+ } catch (err) {
695
+ // @ts-ignore
696
+ throw new Error(err.response.data.message ?? err.message);
697
+ }
698
+ };
699
+
700
+ getProductType = async (id: string): Promise<ProductType> => {
701
+ try {
702
+ const result = await this.httpService.get(`/product-types/${id}`, {});
703
+ return result.data;
704
+ } catch (err) {
705
+ // @ts-ignore
706
+ throw new Error(err.response.data.message ?? err.message);
707
+ }
708
+ };
709
+
710
+ getProductFilters = async (
711
+ params: ProductFiltersQueryParameters,
712
+ ): Promise<FilterByGroup> => {
713
+ try {
714
+ const result = await this.httpService.get(`/products-filters`, {
715
+ // Join by ";" to handle productTypes with ","
716
+ params: {
717
+ ...params,
718
+ productTypes: params.productTypes?.join(';') ?? [],
719
+ filterKeys: params.filterKeys?.join(';') ?? [],
720
+ },
721
+ });
722
+ return result.data;
723
+ } catch (err) {
724
+ // @ts-ignore
725
+ throw new Error(err.response.data.message ?? err.message);
726
+ }
727
+ };
728
+
729
+ getProductSortOptions = async (
730
+ isoLanguageId?: IsoLanguageIds,
731
+ ): Promise<SortOptionsResponse> => {
732
+ try {
733
+ const result = await this.httpService.get(`/product-sort-options`, {
734
+ params: { isoLanguageId },
735
+ });
736
+ return result.data;
737
+ } catch (err) {
738
+ // @ts-ignore
739
+ throw new Error(err.response.data.message ?? err.message);
740
+ }
741
+ };
742
+
743
+ getProductRecommendations = async (id: string): Promise<SelectablePartialProduct[]> => {
744
+ try {
745
+ const result = await this.httpService.get<{ data: Partial<GridProduct>[] }>(
746
+ `/product-recommendations/${id}`,
747
+ {},
748
+ );
749
+
750
+ const response = result.data.map(this.buildSelectableProduct);
751
+
752
+ return response;
753
+ } catch (err) {
754
+ // @ts-ignore
755
+ throw new Error(err.response.data.message ?? err.message);
756
+ }
757
+ };
758
+
759
+ getProductRecommendationsByProductId = async (
760
+ id: string,
761
+ params: Partial<ProductRecommendationsQueryParameters>,
762
+ ): Promise<ProductRecommendationLibraryResponse> => {
763
+ try {
764
+ const result = await this.httpService.get<{ data: ProductRecommendationResponse }>(
765
+ `/product-recommendations-by-productId/${id}`,
766
+ {
767
+ params,
768
+ },
769
+ );
770
+
771
+ const response = {
772
+ default: result?.data?.default?.map(this.buildSelectableProduct),
773
+ similar: result?.data?.similar?.map(this.buildSelectableProduct),
774
+ styleWith: result?.data?.styleWith?.map(this.buildSelectableProduct),
775
+ similarItems: result?.data?.similarItems?.map(this.buildSelectableProduct),
776
+ completeTheLook: result?.data?.completeTheLook?.map(this.buildSelectableProduct),
777
+ };
778
+
779
+ return response;
780
+ } catch (err) {
781
+ // @ts-ignore
782
+ throw new Error(err.response.data.message ?? err.message);
783
+ }
784
+ };
785
+
786
+ getProductRecommendationsByProductIdV2 = async (
787
+ id: string,
788
+ payload: JSONValue,
789
+ ): Promise<SelectablePartialProduct[]> => {
790
+ try {
791
+ const result = await this.httpService.get<{ data: Partial<GridProduct>[] }>(
792
+ `/products/${id}/recommendations`,
793
+ {
794
+ params: {
795
+ payload: JSON.stringify(payload),
796
+ },
797
+ },
798
+ );
799
+
800
+ const response = result.data.map(this.buildSelectableProduct);
801
+
802
+ return response;
803
+ } catch (err) {
804
+ // @ts-ignore
805
+ throw new Error(err.response.data.message ?? err.message);
806
+ }
807
+ };
808
+
809
+ getVariantsList = async (productIds: string[]): Promise<VariantInfo[]> => {
810
+ try {
811
+ const result = await this.httpService.get(`/variants`, {
812
+ params: {
813
+ productIds: productIds.join(','),
814
+ },
815
+ });
816
+ return result.data;
817
+ } catch (err) {
818
+ // @ts-ignore
819
+ throw new Error(err.response.data.message ?? err.message);
820
+ }
821
+ };
822
+
823
+ getVariantsListByIds = async (productIds: string[]): Promise<VariantInfo[]> => {
824
+ try {
825
+ const result = await this.httpService.get(`/variants`, {
826
+ baseURL: `${this.apiEndpoint}/tenants/${this.tenantId}`,
827
+ params: {
828
+ productIds: productIds.join(','),
829
+ },
830
+ });
831
+ return result.data;
832
+ } catch (err) {
833
+ // @ts-ignore
834
+ throw new Error(err.response.data.message ?? err.message);
835
+ }
836
+ };
837
+
838
+ getVariantDetails = async (productId: string): Promise<VariantInfo> => {
839
+ try {
840
+ const result = await this.httpService.get(`/variants/${productId}`, {});
841
+ return result.data;
842
+ } catch (err) {
843
+ // @ts-ignore
844
+ throw new Error(err.response.data.message ?? err.message);
845
+ }
846
+ };
847
+
848
+ getProductEanByEpc = async (epc: string): Promise<string> => {
849
+ try {
850
+ const result = await this.httpService.get(`/product-ean-by-epc/${epc}`, {});
851
+ return result.data;
852
+ } catch (err) {
853
+ // @ts-ignore
854
+ throw new Error(err.response.data.message ?? err.message);
855
+ }
856
+ };
857
+
858
+ getProductByEpc = async (
859
+ code: string,
860
+ params: ProductDetailsByCodeQueryParameters,
861
+ ): Promise<{
862
+ productDetails: SelectablePartialProduct;
863
+ productId: string;
864
+ }> => {
865
+ try {
866
+ const result = await this.httpService.get<{
867
+ data: {
868
+ productDetails: Partial<GridProduct>;
869
+ productId: string;
870
+ };
871
+ }>(`/products-by-epc/${code}`, {
872
+ params,
873
+ });
874
+
875
+ const response = {
876
+ ...result.data,
877
+ productDetails: this.buildSelectableProduct(result.data.productDetails),
878
+ };
879
+
880
+ return response;
881
+ } catch (err) {
882
+ // @ts-ignore
883
+ throw new Error(err.response.data.message ?? err.message);
884
+ }
885
+ };
886
+
887
+ getProductInventory = async ({
888
+ deviceId,
889
+ requestedQty,
890
+ skuId,
891
+ }: {
892
+ deviceId?: string;
893
+ requestedQty: number;
894
+ skuId: string;
895
+ }): Promise<InventoryItem | null> => {
896
+ try {
897
+ const result = await this.httpService.get<{ data: InventoryItem | null }>(
898
+ `/products-inventory`,
899
+ {
900
+ params: { deviceId, requestedQty, skuId },
901
+ },
902
+ );
903
+ return result.data;
904
+ } catch (err) {
905
+ // @ts-ignore
906
+ throw new Error(err.response.data.message ?? err.message);
907
+ }
908
+ };
909
+
910
+ getVariantInventory = async ({
911
+ productId,
912
+ spaceId,
913
+ }: {
914
+ productId: string;
915
+ spaceId?: string;
916
+ }): Promise<VariantInventory> => {
917
+ try {
918
+ const result = await this.httpService.get<{ data: VariantInventory }>(
919
+ `/variants/${productId}/inventory`,
920
+ {
921
+ params: { spaceId },
922
+ },
923
+ );
924
+ return result.data;
925
+ } catch (err) {
926
+ // @ts-ignore
927
+ throw new Error(err.response.data.message ?? err.message);
928
+ }
929
+ };
930
+
931
+ getProductGroupStoresInventory = async (
932
+ params: ProductGroupStoresInventoryParam,
933
+ ): Promise<ProductGroupStoresInventoryResponse | null> => {
934
+ try {
935
+ const result = await this.httpService.get<{
936
+ data: ProductGroupStoresInventoryResponse | null;
937
+ }>(`/product-group-stores-inventory`, {
938
+ params,
939
+ });
940
+ return result.data;
941
+ } catch (err) {
942
+ // @ts-ignore
943
+ throw new Error(err.response.data.message ?? err.message);
944
+ }
945
+ };
946
+
947
+ getCartPromotions = async (
948
+ params: GetCartPromotionsParams,
949
+ ): Promise<GetCartPromotionsResponse | null> => {
950
+ try {
951
+ const { transactionTotal, items } = params;
952
+
953
+ const result = await this.httpService.get<{
954
+ data: GetCartPromotionsResponse | null;
955
+ }>(`/cart/promotions`, {
956
+ params: {
957
+ ...params,
958
+ transactionTotal: transactionTotal.toFixed(2),
959
+ items: JSON.stringify(
960
+ items.map((item) => ({
961
+ ...item,
962
+ sequenceId: item.sequenceId.toString(),
963
+ price: item.price.toFixed(2),
964
+ quantity: item.quantity.toString(),
965
+ })),
966
+ ),
967
+ },
968
+ });
969
+
970
+ return result.data;
971
+ } catch (err) {
972
+ // @ts-ignore
973
+ throw new Error(err.response.data.message ?? err.message);
974
+ }
975
+ };
976
+
977
+ getVariantActivePrice = async (
978
+ params: GetVariantActivePriceParams,
979
+ ): Promise<GetVariantActivePriceResponse | null> => {
980
+ try {
981
+ const result = await this.httpService.get(
982
+ `/variant-active-price/${params.productId}`,
983
+ {
984
+ params,
985
+ },
986
+ );
987
+ return result.data;
988
+ } catch (err) {
989
+ // @ts-ignore
990
+ throw new Error(err.response.data.message ?? err.message);
991
+ }
992
+ };
993
+ }
994
+
995
+ export default GridProductServiceClient;