@reactionary/provider-commercetools 0.3.11 → 0.3.13

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.
@@ -16,7 +16,8 @@ import {
16
16
  CommercetoolsOrderProvider,
17
17
  CommercetoolsOrderSearchProvider,
18
18
  CommercetoolsProfileProvider,
19
- CommercetoolsStoreProvider
19
+ CommercetoolsStoreProvider,
20
+ CommercetoolsProductReviewsProvider
20
21
  } from "../providers/index.js";
21
22
  import { CommercetoolsAPI } from "./client.js";
22
23
  function withCommercetoolsCapabilities(configuration, capabilities) {
@@ -49,6 +50,14 @@ function withCommercetoolsCapabilities(configuration, capabilities) {
49
50
  commercetoolsApi
50
51
  );
51
52
  }
53
+ if (caps.productReviews) {
54
+ client.productReviews = new CommercetoolsProductReviewsProvider(
55
+ config,
56
+ cache,
57
+ context,
58
+ commercetoolsApi
59
+ );
60
+ }
52
61
  if (caps.identity) {
53
62
  client.identity = new CommercetoolsIdentityProvider(
54
63
  config,
package/index.js CHANGED
@@ -6,6 +6,7 @@ export * from "./providers/inventory.provider.js";
6
6
  export * from "./providers/order-search.provider.js";
7
7
  export * from "./providers/price.provider.js";
8
8
  export * from "./providers/product.provider.js";
9
+ export * from "./providers/product-reviews.provider.js";
9
10
  export * from "./providers/product-search.provider.js";
10
11
  export * from "./schema/capabilities.schema.js";
11
12
  export * from "./schema/configuration.schema.js";
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@reactionary/provider-commercetools",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
7
- "@reactionary/core": "0.3.11",
7
+ "@reactionary/core": "0.3.13",
8
8
  "debug": "^4.4.3",
9
9
  "zod": "4.1.9",
10
10
  "@commercetools/ts-client": "^4.2.1",
@@ -5,6 +5,7 @@ export * from "./inventory.provider.js";
5
5
  export * from "./order-search.provider.js";
6
6
  export * from "./price.provider.js";
7
7
  export * from "./product.provider.js";
8
+ export * from "./product-reviews.provider.js";
8
9
  export * from "./profile.provider.js";
9
10
  export * from "./product-search.provider.js";
10
11
  export * from "./store.provider.js";
@@ -0,0 +1,183 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ import {
13
+ ProductReviewsProvider,
14
+ Reactionary,
15
+ success,
16
+ error,
17
+ ProductReviewSchema,
18
+ ProductRatingSummarySchema,
19
+ ProductReviewPaginatedResultSchema
20
+ } from "@reactionary/core";
21
+ class CommercetoolsProductReviewsProvider extends ProductReviewsProvider {
22
+ constructor(config, cache, context, commercetools) {
23
+ super(cache, context);
24
+ this.config = config;
25
+ this.commercetools = commercetools;
26
+ }
27
+ async getClient() {
28
+ const client = await this.commercetools.getClient();
29
+ return client.withProjectKey({ projectKey: this.config.projectKey });
30
+ }
31
+ async getAdminClient() {
32
+ const client = await this.commercetools.getAdminClient();
33
+ return client.withProjectKey({ projectKey: this.config.projectKey });
34
+ }
35
+ async getRatingSummary(query) {
36
+ const client = await this.getClient();
37
+ const response = await client.productProjections().withKey({ key: query.product.key }).get().execute().catch((e) => {
38
+ if (e.statusCode === 404) {
39
+ return null;
40
+ }
41
+ throw e;
42
+ });
43
+ if (response && response.body) {
44
+ const summary = {
45
+ identifier: {
46
+ product: query.product
47
+ },
48
+ averageRating: 0,
49
+ totalRatings: 0
50
+ };
51
+ if (response.body.reviewRatingStatistics) {
52
+ summary.averageRating = response.body.reviewRatingStatistics.averageRating;
53
+ summary.totalRatings = response.body.reviewRatingStatistics.count;
54
+ summary.ratingDistribution = {
55
+ "1": response.body.reviewRatingStatistics.ratingsDistribution["1"] ?? 0,
56
+ "2": response.body.reviewRatingStatistics.ratingsDistribution["2"] ?? 0,
57
+ "3": response.body.reviewRatingStatistics.ratingsDistribution["3"] ?? 0,
58
+ "4": response.body.reviewRatingStatistics.ratingsDistribution["4"] ?? 0,
59
+ "5": response.body.reviewRatingStatistics.ratingsDistribution["5"] ?? 0
60
+ };
61
+ }
62
+ return success(summary);
63
+ } else {
64
+ return success(this.createEmptyProductRatingSummary({ product: query.product }));
65
+ }
66
+ }
67
+ async findReviews(query) {
68
+ const client = await this.getClient();
69
+ const pageNumber = query.paginationOptions?.pageNumber ?? 1;
70
+ const pageSize = query.paginationOptions?.pageSize ?? 20;
71
+ const offset = (pageNumber - 1) * pageSize;
72
+ const product = await client.productProjections().withKey({ key: query.product.key }).get().execute().catch((e) => {
73
+ if (e.statusCode === 404) {
74
+ return null;
75
+ }
76
+ throw e;
77
+ });
78
+ if (!product || !product.body) {
79
+ return success({
80
+ items: [],
81
+ totalCount: 0,
82
+ pageSize,
83
+ pageNumber,
84
+ totalPages: 0
85
+ });
86
+ }
87
+ const whereClause = `target(typeId="product" and id="${product.body.id}")`;
88
+ const sort = ["createdAt desc"];
89
+ const response = await client.reviews().get({
90
+ queryArgs: {
91
+ where: whereClause,
92
+ limit: pageSize,
93
+ offset,
94
+ sort
95
+ }
96
+ }).execute();
97
+ const reviews = response.body.results.map(
98
+ (review) => this.parseSingle(review, query.product.key)
99
+ );
100
+ const returnedResult = {
101
+ items: reviews,
102
+ totalCount: response.body.total || reviews.length,
103
+ pageSize,
104
+ pageNumber,
105
+ totalPages: Math.ceil((response.body.total || reviews.length) / Math.max(pageSize, 1))
106
+ };
107
+ return success(returnedResult);
108
+ }
109
+ async submitReview(mutation) {
110
+ if (!(this.context.session.identityContext.identity.type === "Registered")) {
111
+ return error({ type: "InvalidInput", error: "Only registered users can submit reviews." });
112
+ }
113
+ const client = await this.getAdminClient();
114
+ const response = await client.reviews().post({
115
+ body: {
116
+ authorName: mutation.authorName,
117
+ title: mutation.title,
118
+ text: mutation.content,
119
+ rating: mutation.rating,
120
+ customer: {
121
+ typeId: "customer",
122
+ id: this.context.session.identityContext.identity.id.userId
123
+ },
124
+ target: {
125
+ typeId: "product",
126
+ id: mutation.product.key
127
+ },
128
+ locale: this.context.languageContext.locale
129
+ }
130
+ }).execute();
131
+ const review = this.parseSingle(response.body, mutation.product.key);
132
+ return success(review);
133
+ }
134
+ parseSingle(review, productKey) {
135
+ return {
136
+ identifier: {
137
+ key: review.key || ""
138
+ },
139
+ product: {
140
+ key: productKey
141
+ },
142
+ authorName: review.authorName ?? "Anonymous",
143
+ authorId: review.customer?.id,
144
+ rating: review.rating ?? 0,
145
+ title: review.title ?? "",
146
+ content: review.text ?? "",
147
+ createdAt: review.createdAt,
148
+ updatedAt: review.lastModifiedAt,
149
+ verified: !!review.customer
150
+ // Verified if linked to a customer
151
+ };
152
+ }
153
+ }
154
+ __decorateClass([
155
+ Reactionary({
156
+ outputSchema: ProductRatingSummarySchema,
157
+ cache: true,
158
+ cacheTimeToLiveInSeconds: 300,
159
+ currencyDependentCaching: false,
160
+ localeDependentCaching: false
161
+ })
162
+ ], CommercetoolsProductReviewsProvider.prototype, "getRatingSummary", 1);
163
+ __decorateClass([
164
+ Reactionary({
165
+ outputSchema: ProductReviewPaginatedResultSchema,
166
+ cache: true,
167
+ cacheTimeToLiveInSeconds: 60,
168
+ currencyDependentCaching: false,
169
+ localeDependentCaching: true
170
+ })
171
+ ], CommercetoolsProductReviewsProvider.prototype, "findReviews", 1);
172
+ __decorateClass([
173
+ Reactionary({
174
+ outputSchema: ProductReviewSchema,
175
+ cache: false,
176
+ cacheTimeToLiveInSeconds: 0,
177
+ currencyDependentCaching: false,
178
+ localeDependentCaching: false
179
+ })
180
+ ], CommercetoolsProductReviewsProvider.prototype, "submitReview", 1);
181
+ export {
182
+ CommercetoolsProductReviewsProvider
183
+ };
@@ -2,6 +2,7 @@ import { CapabilitiesSchema } from "@reactionary/core";
2
2
  const CommercetoolsCapabilitiesSchema = CapabilitiesSchema.pick({
3
3
  product: true,
4
4
  productSearch: true,
5
+ productReviews: true,
5
6
  identity: true,
6
7
  cart: true,
7
8
  checkout: true,
package/src/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from './providers/inventory.provider.js';
6
6
  export * from './providers/order-search.provider.js';
7
7
  export * from './providers/price.provider.js';
8
8
  export * from './providers/product.provider.js';
9
+ export * from './providers/product-reviews.provider.js';
9
10
  export * from './providers/product-search.provider.js';
10
11
  export * from './schema/capabilities.schema.js';
11
12
  export * from './schema/configuration.schema.js';
@@ -5,6 +5,7 @@ export * from './inventory.provider.js';
5
5
  export * from './order-search.provider.js';
6
6
  export * from './price.provider.js';
7
7
  export * from './product.provider.js';
8
+ export * from './product-reviews.provider.js';
8
9
  export * from './profile.provider.js';
9
10
  export * from './product-search.provider.js';
10
11
  export * from './store.provider.js';
@@ -0,0 +1,16 @@
1
+ import { ProductReviewsProvider } from '@reactionary/core';
2
+ import type { ProductReview, ProductRatingSummary, ProductReviewPaginatedResult, ProductReviewsListQuery, ProductReviewsGetRatingSummaryQuery, ProductReviewMutationSubmit, Result, RequestContext, Cache } from '@reactionary/core';
3
+ import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
4
+ import type { CommercetoolsAPI } from '../core/client.js';
5
+ import type { Review as CTReview } from '@commercetools/platform-sdk';
6
+ export declare class CommercetoolsProductReviewsProvider extends ProductReviewsProvider {
7
+ protected config: CommercetoolsConfiguration;
8
+ protected commercetools: CommercetoolsAPI;
9
+ constructor(config: CommercetoolsConfiguration, cache: Cache, context: RequestContext, commercetools: CommercetoolsAPI);
10
+ protected getClient(): Promise<import("@commercetools/platform-sdk").ByProjectKeyRequestBuilder>;
11
+ protected getAdminClient(): Promise<import("@commercetools/platform-sdk").ByProjectKeyRequestBuilder>;
12
+ getRatingSummary(query: ProductReviewsGetRatingSummaryQuery): Promise<Result<ProductRatingSummary>>;
13
+ findReviews(query: ProductReviewsListQuery): Promise<Result<ProductReviewPaginatedResult>>;
14
+ submitReview(mutation: ProductReviewMutationSubmit): Promise<Result<ProductReview>>;
15
+ protected parseSingle(review: CTReview, productKey: string): ProductReview;
16
+ }
@@ -1,7 +1,7 @@
1
1
  import type * as z from 'zod';
2
2
  export declare const CommercetoolsCapabilitiesSchema: z.ZodObject<{
3
- price: z.ZodOptional<z.ZodBoolean>;
4
3
  product: z.ZodOptional<z.ZodBoolean>;
4
+ price: z.ZodOptional<z.ZodBoolean>;
5
5
  order: z.ZodOptional<z.ZodBoolean>;
6
6
  cart: z.ZodOptional<z.ZodBoolean>;
7
7
  checkout: z.ZodOptional<z.ZodBoolean>;
@@ -11,6 +11,7 @@ export declare const CommercetoolsCapabilitiesSchema: z.ZodObject<{
11
11
  profile: z.ZodOptional<z.ZodBoolean>;
12
12
  store: z.ZodOptional<z.ZodBoolean>;
13
13
  productSearch: z.ZodOptional<z.ZodBoolean>;
14
+ productReviews: z.ZodOptional<z.ZodBoolean>;
14
15
  orderSearch: z.ZodOptional<z.ZodBoolean>;
15
16
  }, z.core.$loose>;
16
17
  export type CommercetoolsCapabilities = z.infer<typeof CommercetoolsCapabilitiesSchema>;