@infrab4a/connect-angular 5.1.0 → 6.0.0-alpha.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 (212) hide show
  1. package/eslint.config.js +18 -0
  2. package/index.ts +1 -0
  3. package/karma.conf.js +32 -0
  4. package/ng-package.json +8 -0
  5. package/package.json +10 -28
  6. package/project.json +37 -0
  7. package/src/angular-connect.module.ts +256 -0
  8. package/src/angular-elastic-search.module.ts +23 -0
  9. package/src/angular-firebase-auth.module.ts +101 -0
  10. package/src/angular-firestore.module.ts +371 -0
  11. package/src/angular-hasura-graphql.module.ts +219 -0
  12. package/src/angular-vertex-search.module.ts +23 -0
  13. package/src/consts/backend-url.const.ts +1 -0
  14. package/src/consts/category-structure.ts +1 -0
  15. package/src/consts/default-shop.const.ts +1 -0
  16. package/src/consts/es-config.const.ts +1 -0
  17. package/src/consts/firebase-const.ts +5 -0
  18. package/src/consts/hasura-options.const.ts +1 -0
  19. package/src/consts/index.ts +8 -0
  20. package/src/consts/persistence.const.ts +1 -0
  21. package/src/consts/storage-base-url.const.ts +1 -0
  22. package/src/consts/vertex-config.const.ts +1 -0
  23. package/src/helpers/index.ts +1 -0
  24. package/src/helpers/mobile-operation-system-checker.helper.ts +10 -0
  25. package/src/index.ts +6 -0
  26. package/src/interfaces/catalog-strategies.interface.ts +36 -0
  27. package/src/interfaces/category-facades.interface.ts +7 -0
  28. package/src/interfaces/index.ts +2 -0
  29. package/src/persistence/cookie-data-persistence.ts +21 -0
  30. package/src/persistence/data-persistence.ts +7 -0
  31. package/src/persistence/index.ts +2 -0
  32. package/src/services/auth.service.ts +39 -0
  33. package/src/services/cart/cart-services.facade.ts +14 -0
  34. package/src/services/cart/index.ts +1 -0
  35. package/src/services/cart.service.ts +124 -0
  36. package/src/services/catalog/adapters/category-structure.adapter.ts +5 -0
  37. package/src/services/catalog/adapters/index.ts +3 -0
  38. package/src/services/catalog/adapters/new-category-structure.adapter.ts +42 -0
  39. package/src/services/catalog/adapters/old-category-structure.adapter.ts +17 -0
  40. package/src/services/catalog/catalog.service.ts +153 -0
  41. package/src/services/catalog/category.service.ts +52 -0
  42. package/src/services/catalog/context/catalog-search.context.ts +61 -0
  43. package/src/services/catalog/enums/index.ts +1 -0
  44. package/src/services/catalog/enums/product-sorts.enum.ts +9 -0
  45. package/src/services/catalog/facades/catalog-service.facade.ts +32 -0
  46. package/src/services/catalog/facades/catalog-strategies.facade.ts +12 -0
  47. package/src/services/catalog/facades/category-repository.facade.ts +10 -0
  48. package/src/services/catalog/facades/category-service.facade.ts +25 -0
  49. package/src/services/catalog/facades/index.ts +5 -0
  50. package/src/services/catalog/facades/product-catalog.facade.ts +13 -0
  51. package/src/services/catalog/helpers/brand-manager.helper.ts +63 -0
  52. package/src/services/catalog/helpers/catalog-filter.helper.ts +50 -0
  53. package/src/services/catalog/helpers/catalog-sort.helper.ts +54 -0
  54. package/src/services/catalog/helpers/index.ts +4 -0
  55. package/src/services/catalog/helpers/product-fields.helper.ts +35 -0
  56. package/src/services/catalog/index.ts +7 -0
  57. package/src/services/catalog/models/category-with-tree.model.ts +7 -0
  58. package/src/services/catalog/models/index.ts +1 -0
  59. package/src/services/catalog/services/catalog-helpers.service.ts +35 -0
  60. package/src/services/catalog/services/catalog-operations.facade.ts +24 -0
  61. package/src/services/catalog/services/catalog-repository.service.ts +20 -0
  62. package/src/services/catalog/services/index.ts +4 -0
  63. package/src/services/catalog/services/product-management.facade.ts +20 -0
  64. package/src/services/catalog/strategies/category-search.strategy.ts +172 -0
  65. package/src/services/catalog/strategies/index.ts +3 -0
  66. package/src/services/catalog/strategies/profile-search.strategy.ts +51 -0
  67. package/src/services/catalog/strategies/term-search.strategy.ts +178 -0
  68. package/src/services/catalog/strategies/types/strategy-params.type.ts +58 -0
  69. package/src/services/catalog/types/fetch-products-options.type.ts +10 -0
  70. package/src/services/catalog/types/fetch-products-params.type.ts +27 -0
  71. package/src/services/catalog/types/fetch-products-response.type.ts +11 -0
  72. package/src/services/catalog/types/index.ts +5 -0
  73. package/src/services/catalog/types/method-params.type.ts +21 -0
  74. package/src/services/catalog/types/product-sort.type.ts +3 -0
  75. package/src/services/catalog/wishlist.service.ts +368 -0
  76. package/src/services/checkout/checkout-dependencies.facade.ts +13 -0
  77. package/src/services/checkout/checkout-repositories.facade.ts +10 -0
  78. package/src/services/checkout/index.ts +2 -0
  79. package/src/services/checkout-subscription.service.ts +76 -0
  80. package/src/services/checkout.service.ts +196 -0
  81. package/src/services/coupon/coupon-repositories.facade.ts +11 -0
  82. package/src/services/coupon/index.ts +1 -0
  83. package/src/services/coupon/types/coupon-params.type.ts +15 -0
  84. package/src/services/coupon.service.ts +347 -0
  85. package/src/services/errors/group-invalid-coupon.error.ts +9 -0
  86. package/src/services/errors/index.ts +2 -0
  87. package/src/services/errors/invalid-coupon.error.ts +7 -0
  88. package/src/services/helpers/index.ts +1 -0
  89. package/src/services/helpers/util.helper.ts +17 -0
  90. package/src/services/home-shop/home-shop-repositories.facade.ts +11 -0
  91. package/src/services/home-shop/index.ts +1 -0
  92. package/src/services/home-shop.service.ts +196 -0
  93. package/src/services/index.ts +9 -0
  94. package/src/services/order.service.ts +23 -0
  95. package/src/services/shared/configuration.facade.ts +21 -0
  96. package/src/services/shared/index.ts +1 -0
  97. package/src/services/types/index.ts +2 -0
  98. package/src/services/types/required-checkout-data.type.ts +3 -0
  99. package/src/services/types/required-checkout-subscription-data.type.ts +3 -0
  100. package/src/types/firebase-app-config.type.ts +1 -0
  101. package/src/types/index.ts +1 -0
  102. package/tsconfig.json +17 -0
  103. package/tsconfig.lib.json +13 -0
  104. package/tsconfig.lib.prod.json +13 -0
  105. package/tsconfig.spec.json +17 -0
  106. package/angular-connect.module.d.ts +0 -26
  107. package/angular-elastic-search.module.d.ts +0 -9
  108. package/angular-firebase-auth.module.d.ts +0 -11
  109. package/angular-firestore.module.d.ts +0 -18
  110. package/angular-hasura-graphql.module.d.ts +0 -16
  111. package/consts/backend-url.const.d.ts +0 -1
  112. package/consts/category-structure.d.ts +0 -1
  113. package/consts/default-shop.const.d.ts +0 -1
  114. package/consts/es-config.const.d.ts +0 -1
  115. package/consts/firebase-const.d.ts +0 -3
  116. package/consts/hasura-options.const.d.ts +0 -1
  117. package/consts/index.d.ts +0 -7
  118. package/consts/persistence.const.d.ts +0 -1
  119. package/consts/storage-base-url.const.d.ts +0 -1
  120. package/esm2020/angular-connect.module.mjs +0 -115
  121. package/esm2020/angular-elastic-search.module.mjs +0 -34
  122. package/esm2020/angular-firebase-auth.module.mjs +0 -115
  123. package/esm2020/angular-firestore.module.mjs +0 -504
  124. package/esm2020/angular-hasura-graphql.module.mjs +0 -265
  125. package/esm2020/consts/backend-url.const.mjs +0 -2
  126. package/esm2020/consts/category-structure.mjs +0 -2
  127. package/esm2020/consts/default-shop.const.mjs +0 -2
  128. package/esm2020/consts/es-config.const.mjs +0 -2
  129. package/esm2020/consts/firebase-const.mjs +0 -4
  130. package/esm2020/consts/hasura-options.const.mjs +0 -2
  131. package/esm2020/consts/index.mjs +0 -8
  132. package/esm2020/consts/persistence.const.mjs +0 -2
  133. package/esm2020/consts/storage-base-url.const.mjs +0 -2
  134. package/esm2020/helpers/index.mjs +0 -2
  135. package/esm2020/helpers/mobile-operation-system-checker.helper.mjs +0 -7
  136. package/esm2020/index.mjs +0 -7
  137. package/esm2020/infrab4a-connect-angular.mjs +0 -5
  138. package/esm2020/persistence/cookie-data-persistence.mjs +0 -22
  139. package/esm2020/persistence/data-persistence.mjs +0 -2
  140. package/esm2020/persistence/index.mjs +0 -3
  141. package/esm2020/services/auth.service.mjs +0 -37
  142. package/esm2020/services/cart.service.mjs +0 -281
  143. package/esm2020/services/catalog/adapters/category-structure.adapter.mjs +0 -2
  144. package/esm2020/services/catalog/adapters/index.mjs +0 -4
  145. package/esm2020/services/catalog/adapters/new-category-structure.adapter.mjs +0 -43
  146. package/esm2020/services/catalog/adapters/old-category-structure.adapter.mjs +0 -23
  147. package/esm2020/services/catalog/catalog.service.mjs +0 -194
  148. package/esm2020/services/catalog/category.service.mjs +0 -51
  149. package/esm2020/services/catalog/enums/index.mjs +0 -2
  150. package/esm2020/services/catalog/enums/product-sorts.enum.mjs +0 -11
  151. package/esm2020/services/catalog/index.mjs +0 -8
  152. package/esm2020/services/catalog/models/category-with-tree.model.mjs +0 -10
  153. package/esm2020/services/catalog/models/index.mjs +0 -2
  154. package/esm2020/services/catalog/types/index.mjs +0 -2
  155. package/esm2020/services/catalog/types/product-sort.type.mjs +0 -2
  156. package/esm2020/services/catalog/wishlist.service.mjs +0 -115
  157. package/esm2020/services/checkout-subscription.service.mjs +0 -50
  158. package/esm2020/services/checkout.service.mjs +0 -68
  159. package/esm2020/services/coupon.service.mjs +0 -235
  160. package/esm2020/services/helpers/index.mjs +0 -2
  161. package/esm2020/services/helpers/util.helper.mjs +0 -18
  162. package/esm2020/services/home-shop.service.mjs +0 -125
  163. package/esm2020/services/index.mjs +0 -11
  164. package/esm2020/services/order.service.mjs +0 -30
  165. package/esm2020/services/shipping.service.mjs +0 -96
  166. package/esm2020/services/types/index.mjs +0 -3
  167. package/esm2020/services/types/required-checkout-data.type.mjs +0 -2
  168. package/esm2020/services/types/required-checkout-subscription-data.type.mjs +0 -2
  169. package/esm2020/services/types/shipping-methods.type.mjs +0 -2
  170. package/esm2020/types/firebase-app-config.type.mjs +0 -2
  171. package/esm2020/types/index.mjs +0 -2
  172. package/fesm2015/infrab4a-connect-angular.mjs +0 -2417
  173. package/fesm2015/infrab4a-connect-angular.mjs.map +0 -1
  174. package/fesm2020/infrab4a-connect-angular.mjs +0 -2352
  175. package/fesm2020/infrab4a-connect-angular.mjs.map +0 -1
  176. package/helpers/index.d.ts +0 -1
  177. package/helpers/mobile-operation-system-checker.helper.d.ts +0 -3
  178. package/index.d.ts +0 -6
  179. package/persistence/cookie-data-persistence.d.ts +0 -10
  180. package/persistence/data-persistence.d.ts +0 -6
  181. package/persistence/index.d.ts +0 -2
  182. package/services/auth.service.d.ts +0 -18
  183. package/services/cart.service.d.ts +0 -42
  184. package/services/catalog/adapters/category-structure.adapter.d.ts +0 -4
  185. package/services/catalog/adapters/index.d.ts +0 -3
  186. package/services/catalog/adapters/new-category-structure.adapter.d.ts +0 -12
  187. package/services/catalog/adapters/old-category-structure.adapter.d.ts +0 -10
  188. package/services/catalog/catalog.service.d.ts +0 -86
  189. package/services/catalog/category.service.d.ts +0 -20
  190. package/services/catalog/enums/index.d.ts +0 -1
  191. package/services/catalog/enums/product-sorts.enum.d.ts +0 -9
  192. package/services/catalog/index.d.ts +0 -7
  193. package/services/catalog/models/category-with-tree.model.d.ts +0 -4
  194. package/services/catalog/models/index.d.ts +0 -1
  195. package/services/catalog/types/index.d.ts +0 -1
  196. package/services/catalog/types/product-sort.type.d.ts +0 -2
  197. package/services/catalog/wishlist.service.d.ts +0 -38
  198. package/services/checkout-subscription.service.d.ts +0 -19
  199. package/services/checkout.service.d.ts +0 -24
  200. package/services/coupon.service.d.ts +0 -29
  201. package/services/helpers/index.d.ts +0 -1
  202. package/services/helpers/util.helper.d.ts +0 -3
  203. package/services/home-shop.service.d.ts +0 -26
  204. package/services/index.d.ts +0 -10
  205. package/services/order.service.d.ts +0 -13
  206. package/services/shipping.service.d.ts +0 -19
  207. package/services/types/index.d.ts +0 -2
  208. package/services/types/required-checkout-data.type.d.ts +0 -2
  209. package/services/types/required-checkout-subscription-data.type.d.ts +0 -2
  210. package/services/types/shipping-methods.type.d.ts +0 -12
  211. package/types/firebase-app-config.type.d.ts +0 -1
  212. package/types/index.d.ts +0 -1
@@ -0,0 +1,25 @@
1
+ import { Inject, Injectable } from '@angular/core'
2
+ import { Shops } from '@infrab4a/connect'
3
+
4
+ import { DEFAULT_SHOP } from '../../../consts'
5
+ import { CategoryService } from '../category.service'
6
+
7
+ import { CategoryRepositoryFacade } from './category-repository.facade'
8
+ import { ProductCatalogFacade } from './product-catalog.facade'
9
+
10
+ @Injectable()
11
+ export class CategoryServiceFacade {
12
+ private categoryService: CategoryService
13
+
14
+ constructor(
15
+ private readonly categoryRepositoryFacade: CategoryRepositoryFacade,
16
+ private readonly productCatalogFacade: ProductCatalogFacade,
17
+ @Inject(DEFAULT_SHOP) private readonly shop: Shops,
18
+ ) {
19
+ this.categoryService = new CategoryService(this.categoryRepositoryFacade, this.productCatalogFacade, this.shop)
20
+ }
21
+
22
+ getCategoryService(): CategoryService {
23
+ return this.categoryService
24
+ }
25
+ }
@@ -0,0 +1,5 @@
1
+ export { CatalogServiceFacade } from './catalog-service.facade'
2
+ export { CatalogStrategiesFacade } from './catalog-strategies.facade'
3
+ export { CategoryRepositoryFacade } from './category-repository.facade'
4
+ export { CategoryServiceFacade } from './category-service.facade'
5
+ export { ProductCatalogFacade } from './product-catalog.facade'
@@ -0,0 +1,13 @@
1
+ import { Inject, Injectable } from '@angular/core'
2
+ import { ProductRepository } from '@infrab4a/connect'
3
+
4
+ import { CATEGORY_STRUCTURE } from '../../../consts'
5
+ import { CategoryStructureAdapter } from '../adapters'
6
+
7
+ @Injectable()
8
+ export class ProductCatalogFacade {
9
+ constructor(
10
+ @Inject('ProductRepository') public readonly productRepository: ProductRepository,
11
+ @Inject(CATEGORY_STRUCTURE) public readonly categoryStructureAdapter: CategoryStructureAdapter,
12
+ ) {}
13
+ }
@@ -0,0 +1,63 @@
1
+ import { Injectable } from '@angular/core'
2
+ import { Where, isEmpty } from '@infrab4a/connect'
3
+
4
+ import { CatalogSearchParams } from '../../../interfaces'
5
+ import { ProductCatalogFacade } from '../facades'
6
+
7
+ @Injectable()
8
+ export class BrandManagerHelper {
9
+ private brandsList: Record<string, string[]> = {}
10
+
11
+ constructor(private readonly productCatalog: ProductCatalogFacade) {}
12
+
13
+ async setBrandsList(options: CatalogSearchParams, brands: string[]): Promise<void> {
14
+ const filterBrands = options.filters?.brands
15
+ const indexKey = this.buildIndexBrands(options)
16
+
17
+ if (isEmpty(brands) && options.filters) {
18
+ delete options.filters.brands
19
+ }
20
+
21
+ this.brandsList[indexKey] = this.brandsList[indexKey] || brands || (await this.fetchBrandsOnly(options))
22
+
23
+ this.brandsList[indexKey] = this.brandsList[indexKey].filter(Boolean)
24
+
25
+ if (options.filters) {
26
+ options.filters = {
27
+ ...options.filters,
28
+ brands: filterBrands,
29
+ }
30
+ }
31
+ }
32
+
33
+ getBrandsList(indexKey: string): string[] {
34
+ return this.brandsList[indexKey]
35
+ }
36
+
37
+ buildIndexBrands(options: CatalogSearchParams): string {
38
+ if (options.category) return `category-${options.category.id}`
39
+
40
+ if (options.term) return `term-${options.term}`
41
+
42
+ if (options.profile) return `profile-${options.profile.join(',')}`
43
+
44
+ return ''
45
+ }
46
+
47
+ private async fetchBrandsOnly(options: CatalogSearchParams): Promise<string[]> {
48
+ return this.productCatalog.productRepository
49
+ .findCatalog(
50
+ {
51
+ fields: ['id'],
52
+ filters: {
53
+ published: { operator: Where.EQUALS, value: true },
54
+ },
55
+ options: {
56
+ distinct: ['brand'],
57
+ },
58
+ },
59
+ options.mainGender,
60
+ )
61
+ .then((result) => result.distinct.brand)
62
+ }
63
+ }
@@ -0,0 +1,50 @@
1
+ import { Injectable } from '@angular/core'
2
+ import { Product, RepositoryFindFielters, Where, set } from '@infrab4a/connect'
3
+
4
+ import { CatalogFilters } from '../../../interfaces'
5
+
6
+ @Injectable()
7
+ export class CatalogFilterHelper {
8
+ buildFilterQuery(filters: CatalogFilters): RepositoryFindFielters<Product> {
9
+ const filterQuery = {} as RepositoryFindFielters<Product>
10
+
11
+ if (filters.clubDiscount?.length) {
12
+ set(filterQuery, 'price.subscriberDiscountPercentage', {
13
+ operator: Where.IN,
14
+ value: filters.clubDiscount,
15
+ })
16
+ }
17
+
18
+ if (filters.brands?.length) {
19
+ filterQuery.brand = { operator: Where.IN, value: filters.brands }
20
+ }
21
+
22
+ if (filters.gender?.length) {
23
+ filterQuery.gender = { operator: Where.IN, value: filters.gender }
24
+ }
25
+
26
+ if (filters.prices?.min || filters.prices?.max) {
27
+ const priceField = filters.prices.subscriberPrice ? 'price.subscriberPrice' : 'price.price'
28
+ const priceFilters = [
29
+ ...(filters.prices.min ? [{ operator: Where.GTE, value: Math.floor(filters.prices.min) }] : []),
30
+ ...(filters.prices.max ? [{ operator: Where.LTE, value: Math.ceil(filters.prices.max) }] : []),
31
+ ]
32
+
33
+ set(filterQuery, priceField, priceFilters)
34
+ }
35
+
36
+ if (filters.rate) {
37
+ filterQuery.rate = { operator: Where.GTE, value: filters.rate }
38
+ }
39
+
40
+ if (filters.tags?.length) {
41
+ filterQuery.tags = { operator: Where.LIKE, value: filters.tags }
42
+ }
43
+
44
+ if (filters.customOptions?.length) {
45
+ filterQuery.filters = { operator: Where.LIKE, value: filters.customOptions }
46
+ }
47
+
48
+ return filterQuery
49
+ }
50
+ }
@@ -0,0 +1,54 @@
1
+ import { Injectable } from '@angular/core'
2
+ import { Product, RepositoryOrderBy } from '@infrab4a/connect'
3
+
4
+ @Injectable()
5
+ export class CatalogSortHelper {
6
+ buildSortQuery(sort: string): RepositoryOrderBy<Product> {
7
+ if (!sort || sort === 'most-relevant') return {}
8
+
9
+ switch (sort) {
10
+ case 'best-sellers':
11
+ return {
12
+ shoppingCount: 'desc',
13
+ rate: 'desc',
14
+ stock: 'desc',
15
+ name: 'asc',
16
+ }
17
+
18
+ case 'biggest-price':
19
+ return {
20
+ subscriberPrice: 'desc',
21
+ rate: 'desc',
22
+ shoppingCount: 'desc',
23
+ } as any
24
+
25
+ case 'lowest-price':
26
+ return {
27
+ subscriberPrice: 'asc',
28
+ rate: 'desc',
29
+ shoppingCount: 'desc',
30
+ } as any
31
+
32
+ case 'best-rating':
33
+ return {
34
+ rate: 'desc',
35
+ shoppingCount: 'desc',
36
+ stock: 'desc',
37
+ name: 'asc',
38
+ }
39
+
40
+ case 'news':
41
+ return { createdAt: 'desc' }
42
+
43
+ case 'biggest-discount':
44
+ return {
45
+ subscriberDiscountPercentage: 'desc',
46
+ rate: 'desc',
47
+ shoppingCount: 'desc',
48
+ } as any
49
+
50
+ default:
51
+ return {}
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,4 @@
1
+ export * from './brand-manager.helper'
2
+ export * from './catalog-filter.helper'
3
+ export * from './catalog-sort.helper'
4
+ export * from './product-fields.helper'
@@ -0,0 +1,35 @@
1
+ import { Injectable } from '@angular/core'
2
+ import { NonFunctionPropertyNames, Product } from '@infrab4a/connect'
3
+
4
+ @Injectable()
5
+ export class ProductFieldsHelper {
6
+ getStandardFields(): NonFunctionPropertyNames<Product>[] {
7
+ return [
8
+ 'id',
9
+ 'name',
10
+ 'slug',
11
+ 'images',
12
+ 'miniatures',
13
+ 'price',
14
+ 'stock',
15
+ 'published',
16
+ 'CEST',
17
+ 'EAN',
18
+ 'NCM',
19
+ 'brand',
20
+ 'costPrice',
21
+ 'hasVariants',
22
+ 'isKit',
23
+ 'sku',
24
+ 'rate',
25
+ 'tags',
26
+ 'type',
27
+ 'shoppingCount',
28
+ 'gender',
29
+ 'createdAt',
30
+ 'label',
31
+ 'outlet',
32
+ 'group',
33
+ ]
34
+ }
35
+ }
@@ -0,0 +1,7 @@
1
+ export * from './adapters'
2
+ export * from './catalog.service'
3
+ export * from './category.service'
4
+ export * from './enums'
5
+ export * from './models'
6
+ export * from './types'
7
+ export * from './wishlist.service'
@@ -0,0 +1,7 @@
1
+ import { Type } from 'class-transformer'
2
+ import { Category } from '@infrab4a/connect'
3
+
4
+ export class CategoryWithTree extends Category {
5
+ @Type(() => CategoryWithTree)
6
+ children?: CategoryWithTree[]
7
+ }
@@ -0,0 +1 @@
1
+ export * from './category-with-tree.model'
@@ -0,0 +1,35 @@
1
+ import { Injectable } from '@angular/core'
2
+
3
+ import { ProductServicesFacade } from '../../../interfaces'
4
+ import { BrandManagerHelper, CatalogFilterHelper, CatalogSortHelper, ProductFieldsHelper } from '../helpers'
5
+
6
+ import { CatalogOperationsFacade } from './catalog-operations.facade'
7
+ import { ProductManagementFacade } from './product-management.facade'
8
+
9
+ @Injectable()
10
+ export class CatalogHelpersService {
11
+ constructor(
12
+ private readonly catalogOperations: CatalogOperationsFacade,
13
+ private readonly productManagement: ProductManagementFacade,
14
+ ) {}
15
+
16
+ getFilterHelper(): CatalogFilterHelper {
17
+ return this.catalogOperations.getFilterHelper()
18
+ }
19
+
20
+ getSortHelper(): CatalogSortHelper {
21
+ return this.catalogOperations.getSortHelper()
22
+ }
23
+
24
+ getFieldsHelper(): ProductFieldsHelper {
25
+ return this.catalogOperations.getFieldsHelper()
26
+ }
27
+
28
+ getBrandManager(): BrandManagerHelper {
29
+ return this.productManagement.getBrandManager()
30
+ }
31
+
32
+ getProductServices(): ProductServicesFacade {
33
+ return this.productManagement.getProductServices()
34
+ }
35
+ }
@@ -0,0 +1,24 @@
1
+ import { Injectable } from '@angular/core'
2
+
3
+ import { CatalogFilterHelper, CatalogSortHelper, ProductFieldsHelper } from '../helpers'
4
+
5
+ @Injectable()
6
+ export class CatalogOperationsFacade {
7
+ constructor(
8
+ private readonly filterHelper: CatalogFilterHelper,
9
+ private readonly sortHelper: CatalogSortHelper,
10
+ private readonly fieldsHelper: ProductFieldsHelper,
11
+ ) {}
12
+
13
+ getFilterHelper(): CatalogFilterHelper {
14
+ return this.filterHelper
15
+ }
16
+
17
+ getSortHelper(): CatalogSortHelper {
18
+ return this.sortHelper
19
+ }
20
+
21
+ getFieldsHelper(): ProductFieldsHelper {
22
+ return this.fieldsHelper
23
+ }
24
+ }
@@ -0,0 +1,20 @@
1
+ import { Injectable } from '@angular/core'
2
+
3
+ import { ProductServicesFacade } from '../../../interfaces'
4
+ import { ProductCatalogFacade } from '../facades'
5
+
6
+ @Injectable()
7
+ export class CatalogRepositoryService {
8
+ constructor(
9
+ private readonly productCatalog: ProductCatalogFacade,
10
+ private readonly productServices: ProductServicesFacade,
11
+ ) {}
12
+
13
+ getProductCatalog(): ProductCatalogFacade {
14
+ return this.productCatalog
15
+ }
16
+
17
+ getProductServices(): ProductServicesFacade {
18
+ return this.productServices
19
+ }
20
+ }
@@ -0,0 +1,4 @@
1
+ export { CatalogHelpersService } from './catalog-helpers.service'
2
+ export { CatalogOperationsFacade } from './catalog-operations.facade'
3
+ export * from './catalog-repository.service'
4
+ export { ProductManagementFacade } from './product-management.facade'
@@ -0,0 +1,20 @@
1
+ import { Injectable } from '@angular/core'
2
+
3
+ import { ProductServicesFacade } from '../../../interfaces'
4
+ import { BrandManagerHelper } from '../helpers'
5
+
6
+ @Injectable()
7
+ export class ProductManagementFacade {
8
+ constructor(
9
+ private readonly brandManager: BrandManagerHelper,
10
+ private readonly productServices: ProductServicesFacade,
11
+ ) {}
12
+
13
+ getBrandManager(): BrandManagerHelper {
14
+ return this.brandManager
15
+ }
16
+
17
+ getProductServices(): ProductServicesFacade {
18
+ return this.productServices
19
+ }
20
+ }
@@ -0,0 +1,172 @@
1
+ import { Injectable } from '@angular/core'
2
+ import { Product, RepositoryCacheOptions, RepositoryFindResult, Shops, Where, isEmpty } from '@infrab4a/connect'
3
+
4
+ import { CatalogSearchParams, CatalogSearchStrategy } from '../../../interfaces'
5
+ import { CatalogHelpersService, CatalogRepositoryService } from '../services'
6
+
7
+ import {
8
+ FindAndSortByMostRelevantParams,
9
+ SearchDefaultParams,
10
+ SearchWithMostRelevantParams,
11
+ } from './types/strategy-params.type'
12
+
13
+ @Injectable()
14
+ export class CategorySearchStrategy implements CatalogSearchStrategy {
15
+ constructor(
16
+ private readonly repositoryService: CatalogRepositoryService,
17
+ private readonly helpersService: CatalogHelpersService,
18
+ ) {}
19
+
20
+ async search(
21
+ params: CatalogSearchParams,
22
+ shop: Shops,
23
+ optionsCache?: { cache?: RepositoryCacheOptions },
24
+ ): Promise<RepositoryFindResult<Product>> {
25
+ const { category, filters, limits, sort, mainGender } = params
26
+
27
+ if (!category) {
28
+ throw new Error('Category is required for CategorySearchStrategy')
29
+ }
30
+
31
+ const fields = this.helpersService.getFieldsHelper().getStandardFields()
32
+
33
+ if (sort === 'most-relevant') {
34
+ return this.searchWithMostRelevant({
35
+ category,
36
+ filters,
37
+ limits,
38
+ shop,
39
+ mainGender,
40
+ optionsCache,
41
+ fields,
42
+ })
43
+ }
44
+
45
+ return this.searchDefault({
46
+ category,
47
+ filters,
48
+ limits,
49
+ shop,
50
+ mainGender,
51
+ sort,
52
+ optionsCache,
53
+ fields,
54
+ })
55
+ }
56
+
57
+ private async searchWithMostRelevant(params: SearchWithMostRelevantParams) {
58
+ const { category, filters, shop, optionsCache } = params
59
+ const mostRelevant = category.isWishlist ? [] : category.getMostRelevantByShop(shop)
60
+ const productsIds = await this.getProductIds(category, filters, optionsCache)
61
+
62
+ return this.findAndSortByMostRelevant({
63
+ mostRelevants: mostRelevant,
64
+ productIds: productsIds,
65
+ filters: params.filters,
66
+ limits: params.limits,
67
+ shop: params.shop,
68
+ mainGender: params.mainGender,
69
+ optionsCache: params.optionsCache,
70
+ fields: params.fields,
71
+ })
72
+ }
73
+
74
+ private async searchDefault(params: SearchDefaultParams) {
75
+ const { category, filters, limits, shop, mainGender, sort, optionsCache, fields } = params
76
+ const productCatalog = this.repositoryService.getProductCatalog()
77
+ const filterHelper = this.helpersService.getFilterHelper()
78
+ const sortHelper = this.helpersService.getSortHelper()
79
+
80
+ const repoParams = {
81
+ fields,
82
+ filters: {
83
+ ...(await productCatalog.categoryStructureAdapter.buildProductFilterByCategory(category)),
84
+ ...filterHelper.buildFilterQuery(filters || {}),
85
+ },
86
+ ...(sort ? { orderBy: sortHelper.buildSortQuery(sort) } : {}),
87
+ limits,
88
+ options: {
89
+ minimal: ['price'],
90
+ maximum: ['price'],
91
+ distinct: ['brand'],
92
+ },
93
+ }
94
+
95
+ return productCatalog.productRepository.findCatalog(
96
+ repoParams,
97
+ mainGender || (shop === Shops.MENSMARKET ? 'male' : 'female'),
98
+ optionsCache,
99
+ )
100
+ }
101
+
102
+ private async getProductIds(category: any, filters: any, optionsCache: any): Promise<string[]> {
103
+ const productCatalog = this.repositoryService.getProductCatalog()
104
+ const filterHelper = this.helpersService.getFilterHelper()
105
+
106
+ return productCatalog.productRepository
107
+ .findCatalog(
108
+ {
109
+ fields: ['id'],
110
+ filters: {
111
+ ...(await productCatalog.categoryStructureAdapter.buildProductFilterByCategory(category)),
112
+ ...filterHelper.buildFilterQuery(filters || {}),
113
+ },
114
+ },
115
+ undefined,
116
+ optionsCache,
117
+ )
118
+ .then((products) => products.data.map((product) => product.id))
119
+ }
120
+
121
+ private async findAndSortByMostRelevant(
122
+ params: FindAndSortByMostRelevantParams,
123
+ ): Promise<RepositoryFindResult<Product>> {
124
+ const { mostRelevants, productIds, filters, shop, mainGender, optionsCache, fields, limits } = params
125
+ const productCatalog = this.repositoryService.getProductCatalog()
126
+ const filterHelper = this.helpersService.getFilterHelper()
127
+ const sortHelper = this.helpersService.getSortHelper()
128
+
129
+ const mostRelevantProductsIds = [...new Set(mostRelevants.concat(productIds))]
130
+ const totalResult = await productCatalog.productRepository.findCatalog(
131
+ {
132
+ fields,
133
+ filters: {
134
+ id: { operator: Where.IN, value: mostRelevantProductsIds },
135
+ ...filterHelper.buildFilterQuery(filters || {}),
136
+ },
137
+ orderBy: sortHelper.buildSortQuery('best-sellers'),
138
+ options: {
139
+ minimal: ['price'],
140
+ maximum: ['price'],
141
+ ...(isEmpty(filters?.brands) ? { distinct: ['brand'] } : {}),
142
+ },
143
+ },
144
+ mainGender || (shop === Shops.MENSMARKET ? 'male' : 'female'),
145
+ optionsCache,
146
+ )
147
+
148
+ return this.sortProductsByRelevance(totalResult, mostRelevants, limits)
149
+ }
150
+
151
+ private sortProductsByRelevance(totalResult: any, mostRelevants: string[], limits: any) {
152
+ const mostRelevantWithoutStock = totalResult.data.filter(
153
+ (product: any) => mostRelevants.includes(product.id) && product.stock.quantity <= 0,
154
+ )
155
+ const firstProducts = totalResult.data
156
+ .filter((product: any) => mostRelevants.includes(product.id) && product.stock.quantity > 0)
157
+ .sort((a: any, b: any) => mostRelevants.indexOf(a.id) - mostRelevants.indexOf(b.id))
158
+ const lastProducts = totalResult.data
159
+ .filter((product: any) => !mostRelevants.includes(product.id))
160
+ .concat(mostRelevantWithoutStock)
161
+ const categoryMostRelevants = firstProducts.concat(lastProducts)
162
+ const resultFinal = categoryMostRelevants.slice(limits.offset, limits.offset + limits.limit)
163
+
164
+ return {
165
+ data: resultFinal,
166
+ count: totalResult.count,
167
+ maximum: totalResult.maximum,
168
+ minimal: totalResult.minimal,
169
+ distinct: totalResult.distinct,
170
+ }
171
+ }
172
+ }
@@ -0,0 +1,3 @@
1
+ export * from './category-search.strategy'
2
+ export * from './profile-search.strategy'
3
+ export * from './term-search.strategy'
@@ -0,0 +1,51 @@
1
+ import { Injectable } from '@angular/core'
2
+ import { Product, RepositoryCacheOptions, RepositoryFindResult, Shops, Where } from '@infrab4a/connect'
3
+
4
+ import { CatalogSearchParams, CatalogSearchStrategy } from '../../../interfaces'
5
+ import { CatalogHelpersService, CatalogRepositoryService } from '../services'
6
+
7
+ @Injectable()
8
+ export class ProfileSearchStrategy implements CatalogSearchStrategy {
9
+ constructor(
10
+ private readonly repositoryService: CatalogRepositoryService,
11
+ private readonly helpersService: CatalogHelpersService,
12
+ ) {}
13
+
14
+ async search(
15
+ params: CatalogSearchParams,
16
+ shop: Shops,
17
+ optionsCache?: { cache?: RepositoryCacheOptions },
18
+ ): Promise<RepositoryFindResult<Product>> {
19
+ const { profile, filters, limits, sort, mainGender } = params
20
+
21
+ if (!profile) {
22
+ throw new Error('Profile is required for ProfileSearchStrategy')
23
+ }
24
+
25
+ const productCatalog = this.repositoryService.getProductCatalog()
26
+ const filterHelper = this.helpersService.getFilterHelper()
27
+ const sortHelper = this.helpersService.getSortHelper()
28
+ const fieldsHelper = this.helpersService.getFieldsHelper()
29
+
30
+ const repoParams = {
31
+ fields: fieldsHelper.getStandardFields(),
32
+ filters: {
33
+ tags: { operator: Where.LIKE, value: profile },
34
+ ...filterHelper.buildFilterQuery(filters || {}),
35
+ },
36
+ ...(sort ? { orderBy: sortHelper.buildSortQuery(sort) } : {}),
37
+ limits,
38
+ options: {
39
+ minimal: ['price'],
40
+ maximum: ['price'],
41
+ distinct: ['brand'],
42
+ },
43
+ }
44
+
45
+ return productCatalog.productRepository.findCatalog(
46
+ repoParams,
47
+ mainGender || (shop === Shops.MENSMARKET ? 'male' : 'female'),
48
+ optionsCache,
49
+ )
50
+ }
51
+ }