@shopgate/pwa-common-commerce 7.34.0-beta.1 → 7.34.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/category/constants/Portals.js +4 -0
- package/filter/actions/helpers/buildRequestFilters.d.ts +9 -0
- package/filter/actions/helpers/buildRequestFilters.d.ts.map +1 -0
- package/filter/constants/Pipelines.d.ts +2 -0
- package/filter/constants/Pipelines.d.ts.map +1 -0
- package/filter/selectors/index.d.ts +42 -0
- package/filter/selectors/index.d.ts.map +1 -0
- package/package.json +3 -3
- package/product/constants/Pipelines.d.ts +13 -0
- package/product/constants/Pipelines.d.ts.map +1 -0
- package/product/constants/index.d.ts +67 -0
- package/product/constants/index.d.ts.map +1 -0
- package/product/helpers/index.d.ts +5 -0
- package/product/helpers/index.d.ts.map +1 -0
- package/product/selectors/product.d.ts +513 -0
- package/product/selectors/product.d.ts.map +1 -0
- package/reviews/action-creators/errorProductReviews.d.ts +19 -0
- package/reviews/action-creators/errorProductReviews.d.ts.map +1 -0
- package/reviews/action-creators/errorProductReviews.js +5 -4
- package/reviews/action-creators/errorReviews.d.ts +19 -0
- package/reviews/action-creators/errorReviews.d.ts.map +1 -0
- package/reviews/action-creators/errorReviews.js +5 -4
- package/reviews/action-creators/receiveProductReviews.d.ts +25 -0
- package/reviews/action-creators/receiveProductReviews.d.ts.map +1 -0
- package/reviews/action-creators/receiveProductReviews.js +10 -7
- package/reviews/action-creators/receiveReviewVote.d.ts +18 -0
- package/reviews/action-creators/receiveReviewVote.d.ts.map +1 -0
- package/reviews/action-creators/receiveReviewVote.js +15 -0
- package/reviews/action-creators/receiveReviews.d.ts +29 -0
- package/reviews/action-creators/receiveReviews.d.ts.map +1 -0
- package/reviews/action-creators/receiveReviews.js +13 -8
- package/reviews/action-creators/requestProductReviews.d.ts +21 -0
- package/reviews/action-creators/requestProductReviews.d.ts.map +1 -0
- package/reviews/action-creators/requestProductReviews.js +6 -5
- package/reviews/action-creators/requestReviews.d.ts +19 -0
- package/reviews/action-creators/requestReviews.d.ts.map +1 -0
- package/reviews/action-creators/requestReviews.js +5 -4
- package/reviews/action-creators/reviewSettings.d.ts +31 -0
- package/reviews/action-creators/reviewSettings.d.ts.map +1 -0
- package/reviews/action-creators/reviewSettings.js +28 -0
- package/reviews/actions/fetchProductReviewSettings.d.ts +5 -0
- package/reviews/actions/fetchProductReviewSettings.d.ts.map +1 -0
- package/reviews/actions/fetchProductReviewSettings.js +25 -0
- package/reviews/actions/fetchProductReviews.d.ts +17 -0
- package/reviews/actions/fetchProductReviews.d.ts.map +1 -0
- package/reviews/actions/fetchProductReviews.js +17 -9
- package/reviews/actions/fetchReviews.d.ts +22 -0
- package/reviews/actions/fetchReviews.d.ts.map +1 -0
- package/reviews/actions/fetchReviews.js +48 -14
- package/reviews/actions/submitReviewVote.d.ts +15 -0
- package/reviews/actions/submitReviewVote.d.ts.map +1 -0
- package/reviews/actions/submitReviewVote.js +46 -0
- package/reviews/constants/Pipelines.d.ts +7 -0
- package/reviews/constants/Pipelines.d.ts.map +1 -0
- package/reviews/constants/Pipelines.js +3 -1
- package/reviews/constants/index.d.ts +47 -0
- package/reviews/constants/index.d.ts.map +1 -0
- package/reviews/constants/index.js +43 -1
- package/reviews/helpers/filters.d.ts +16 -0
- package/reviews/helpers/filters.d.ts.map +1 -0
- package/reviews/helpers/filters.js +36 -0
- package/reviews/helpers/summary.d.ts +8 -0
- package/reviews/helpers/summary.d.ts.map +1 -0
- package/reviews/helpers/summary.js +55 -0
- package/reviews/index.js +1 -0
- package/reviews/reducers/index.js +5 -1
- package/reviews/reducers/ownReviewVotes.d.ts +13 -0
- package/reviews/reducers/ownReviewVotes.d.ts.map +1 -0
- package/reviews/reducers/ownReviewVotes.js +23 -0
- package/reviews/reducers/reviewSettings.d.ts +13 -0
- package/reviews/reducers/reviewSettings.d.ts.map +1 -0
- package/reviews/reducers/reviewSettings.js +33 -0
- package/reviews/reducers/reviewSummariesByProductId.d.ts +18 -0
- package/reviews/reducers/reviewSummariesByProductId.d.ts.map +1 -0
- package/reviews/reducers/reviewSummariesByProductId.js +27 -0
- package/reviews/reducers/reviewsByHash.d.ts +25 -0
- package/reviews/reducers/reviewsByHash.d.ts.map +1 -0
- package/reviews/reducers/reviewsByHash.js +70 -27
- package/reviews/reducers/reviewsById.d.ts +20 -0
- package/reviews/reducers/reviewsById.d.ts.map +1 -0
- package/reviews/reducers/reviewsById.js +23 -7
- package/reviews/reducers/reviewsByProductId.d.ts +23 -0
- package/reviews/reducers/reviewsByProductId.d.ts.map +1 -0
- package/reviews/reducers/reviewsByProductId.js +38 -23
- package/reviews/selectors/index.d.ts +278 -0
- package/reviews/selectors/index.d.ts.map +1 -0
- package/reviews/selectors/index.js +167 -56
- package/reviews/selectors/ownReviewVotes.d.ts +9 -0
- package/reviews/selectors/ownReviewVotes.d.ts.map +1 -0
- package/reviews/selectors/ownReviewVotes.js +7 -0
- package/reviews/selectors/reviewSettings.d.ts +63 -0
- package/reviews/selectors/reviewSettings.d.ts.map +1 -0
- package/reviews/selectors/reviewSettings.js +40 -0
- package/reviews/selectors/reviewSummary.d.ts +18 -0
- package/reviews/selectors/reviewSummary.d.ts.map +1 -0
- package/reviews/selectors/reviewSummary.js +45 -0
- package/reviews/streams/index.js +19 -1
- package/reviews/subscriptions/index.js +14 -1
- package/reviews/types/reviewSettings.d.ts +31 -0
- package/reviews/types/reviewSettings.d.ts.map +1 -0
- package/reviews/types/reviewSettings.js +1 -0
- package/reviews/types/reviewSummary.d.ts +16 -0
- package/reviews/types/reviewSummary.d.ts.map +1 -0
- package/reviews/types/reviewSummary.js +1 -0
- package/reviews/types/reviews.d.ts +190 -0
- package/reviews/types/reviews.d.ts.map +1 -0
- package/reviews/types/reviews.js +1 -0
|
@@ -1,33 +1,42 @@
|
|
|
1
1
|
import { createSelector } from 'reselect';
|
|
2
|
+
import { SORT_DATE_DESC } from '@shopgate/pwa-common/constants/DisplayOptions';
|
|
2
3
|
import { generateResultHash } from '@shopgate/pwa-common/helpers/redux';
|
|
3
4
|
import { isUserLoggedIn } from '@shopgate/pwa-common/selectors/user';
|
|
4
|
-
import {
|
|
5
|
+
import { getBaseProductId as getBaseProductIdSelector } from '@shopgate/engage/product/selectors/product';
|
|
5
6
|
import * as pipelines from "../constants/Pipelines";
|
|
6
|
-
import {
|
|
7
|
+
import { areReviewFiltersEqual } from "../helpers/filters";
|
|
8
|
+
import { isReviewCursorPagination } from "./reviewSettings";
|
|
9
|
+
export * from "./reviewSettings";
|
|
10
|
+
export * from "./reviewSummary";
|
|
11
|
+
export * from "./ownReviewVotes";
|
|
12
|
+
const NO_FILTERS = {};
|
|
13
|
+
const getBaseProductId = getBaseProductIdSelector;
|
|
7
14
|
|
|
8
15
|
/**
|
|
9
|
-
*
|
|
10
|
-
* @
|
|
16
|
+
* Selects the reviews slice.
|
|
17
|
+
* @param state The global state.
|
|
18
|
+
* @returns The reviews slice.
|
|
11
19
|
*/
|
|
12
20
|
const getReviewsState = state => state.reviews;
|
|
13
21
|
|
|
14
22
|
/**
|
|
15
|
-
*
|
|
16
|
-
* @
|
|
23
|
+
* Selects the review previews stored by product id.
|
|
24
|
+
* @param state The global state.
|
|
25
|
+
* @returns The review previews stored by product id.
|
|
17
26
|
*/
|
|
18
27
|
const getProductReviewsExcerptState = state => state.reviews.reviewsByProductId;
|
|
19
28
|
|
|
20
29
|
/**
|
|
21
30
|
* Select the product reviews state.
|
|
22
|
-
* @param
|
|
23
|
-
* @
|
|
31
|
+
* @param state The current application state.
|
|
32
|
+
* @returns The product reviews state.
|
|
24
33
|
*/
|
|
25
34
|
const getReviewsByHash = createSelector(getReviewsState, state => state.reviewsByHash);
|
|
26
35
|
|
|
27
36
|
/**
|
|
28
37
|
* Retrieves the fetching state for the current product's reviews.
|
|
29
|
-
* @param
|
|
30
|
-
* @
|
|
38
|
+
* @param state The current application state.
|
|
39
|
+
* @returns The reviews for a product.
|
|
31
40
|
*/
|
|
32
41
|
const getCollectionForCurrentBaseProduct = createSelector(getBaseProductId, getReviewsByHash, (productId, reviews) => {
|
|
33
42
|
const hash = generateResultHash({
|
|
@@ -42,26 +51,26 @@ const getCollectionForCurrentBaseProduct = createSelector(getBaseProductId, getR
|
|
|
42
51
|
|
|
43
52
|
/**
|
|
44
53
|
* Select the product reviews state
|
|
45
|
-
* @param
|
|
46
|
-
* @
|
|
54
|
+
* @param state The current application state.
|
|
55
|
+
* @returns The product reviews state.
|
|
47
56
|
*/
|
|
48
57
|
const getReviewsByProductId = createSelector(getReviewsState, state => state.reviewsByProductId);
|
|
49
58
|
|
|
50
59
|
/**
|
|
51
60
|
* Retrieves the reviews collection which contains all reviews data.
|
|
52
|
-
* @param
|
|
53
|
-
* @
|
|
61
|
+
* @param state The current application state.
|
|
62
|
+
* @returns The reviews collection stored as reviewId => review pairs.
|
|
54
63
|
*/
|
|
55
64
|
export const getReviews = createSelector(getReviewsState, state => state.reviewsById || {});
|
|
56
65
|
|
|
57
66
|
/**
|
|
58
67
|
* Retrieves the number of reviews for a product
|
|
59
|
-
* @param
|
|
60
|
-
* @
|
|
68
|
+
* @param state The current application state.
|
|
69
|
+
* @returns The total review count for a product
|
|
61
70
|
*/
|
|
62
71
|
export const getProductReviewCount = createSelector(getBaseProductId, getReviewsByProductId, (productId, reviewsState) => {
|
|
63
72
|
const collection = reviewsState[productId];
|
|
64
|
-
if (!collection ||
|
|
73
|
+
if (!collection || typeof collection.totalReviewCount !== 'number') {
|
|
65
74
|
return null;
|
|
66
75
|
}
|
|
67
76
|
return collection.totalReviewCount;
|
|
@@ -69,19 +78,19 @@ export const getProductReviewCount = createSelector(getBaseProductId, getReviews
|
|
|
69
78
|
|
|
70
79
|
/**
|
|
71
80
|
* Retrieves the total number of reviews for a current product.
|
|
72
|
-
* @param
|
|
73
|
-
* @
|
|
81
|
+
* @param state The current application state.
|
|
82
|
+
* @returns The total number of reviews.
|
|
74
83
|
*/
|
|
75
84
|
export const getReviewsTotalCount = createSelector(getCollectionForCurrentBaseProduct, collection => {
|
|
76
|
-
if (!collection ||
|
|
85
|
+
if (!collection || typeof collection.totalReviewCount !== 'number') {
|
|
77
86
|
return null;
|
|
78
87
|
}
|
|
79
88
|
return collection.totalReviewCount;
|
|
80
89
|
});
|
|
81
90
|
/**
|
|
82
91
|
* Retrieves the total number of currently fetched reviews for a current product.
|
|
83
|
-
* @param
|
|
84
|
-
* @
|
|
92
|
+
* @param state The current application state.
|
|
93
|
+
* @returns The current number of fetched reviews.
|
|
85
94
|
*/
|
|
86
95
|
export const getCurrentReviewCount = createSelector(getCollectionForCurrentBaseProduct, collection => {
|
|
87
96
|
if (!collection || !collection.reviews) {
|
|
@@ -90,17 +99,95 @@ export const getCurrentReviewCount = createSelector(getCollectionForCurrentBaseP
|
|
|
90
99
|
return collection.reviews.length;
|
|
91
100
|
});
|
|
92
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Retrieves the sort of the last review list request of the current base product.
|
|
104
|
+
* @param state The current application state.
|
|
105
|
+
* @returns The sort, or the default sort when the list was not requested yet.
|
|
106
|
+
*/
|
|
107
|
+
export const getReviewListSort = createSelector(getCollectionForCurrentBaseProduct, collection => collection?.requestSort ?? SORT_DATE_DESC);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Retrieves the filters of the last review list request of the current base product.
|
|
111
|
+
* @param state The current application state.
|
|
112
|
+
* @returns The active filters; empty when the list is unfiltered or was not requested yet.
|
|
113
|
+
*/
|
|
114
|
+
export const getReviewListFilters = createSelector(getCollectionForCurrentBaseProduct, collection => collection?.requestFilters ?? NO_FILTERS);
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Whether the last request asked for the first page of another sort or filter than the stored
|
|
118
|
+
* reviews were loaded with. The stored reviews then do not belong to the requested list.
|
|
119
|
+
* @param state The current application state.
|
|
120
|
+
* @returns True from the request until its reviews were received, also after it failed.
|
|
121
|
+
*/
|
|
122
|
+
export const isReviewListQueryChanged = createSelector(getCollectionForCurrentBaseProduct, collection => !!collection && collection.requestOffset === 0 && (collection.requestSort !== collection.sort || !areReviewFiltersEqual(collection.requestFilters, collection.filters)));
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Whether the review list of the current base product has a further page.
|
|
126
|
+
* @param state The current application state.
|
|
127
|
+
* @returns True when the provider returned a cursor for the next page or, with offset
|
|
128
|
+
* pagination, fewer reviews are loaded than the list contains.
|
|
129
|
+
*/
|
|
130
|
+
export const hasMoreReviews = createSelector(getCollectionForCurrentBaseProduct, getCurrentReviewCount, getReviewsTotalCount, isReviewCursorPagination, (collection, count, totalCount, isCursor) => {
|
|
131
|
+
if (!count) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
if (isCursor) {
|
|
135
|
+
return !!collection?.after;
|
|
136
|
+
}
|
|
137
|
+
return typeof totalCount === 'number' && count < totalCount;
|
|
138
|
+
});
|
|
139
|
+
|
|
93
140
|
/**
|
|
94
141
|
* Retrieves the information if reviews are currently fetched.
|
|
95
|
-
* @param
|
|
96
|
-
* @
|
|
142
|
+
* @param state The current application state.
|
|
143
|
+
* @returns The boolean information if reviews are currently being fetched.
|
|
97
144
|
*/
|
|
98
145
|
export const getReviewsFetchingState = createSelector(getCollectionForCurrentBaseProduct, collection => collection && collection.isFetching);
|
|
99
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Whether the review list of the current base product was not requested yet.
|
|
149
|
+
* @param state The current application state.
|
|
150
|
+
* @returns True when no list collection exists.
|
|
151
|
+
*/
|
|
152
|
+
export const isReviewListMissing = createSelector(getCollectionForCurrentBaseProduct, collection => collection === null);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Whether the last review list request of the current base product failed.
|
|
156
|
+
* @param state The current application state.
|
|
157
|
+
* @returns True when the last request failed, also when earlier pages are still stored.
|
|
158
|
+
*/
|
|
159
|
+
export const hasReviewListError = createSelector(getCollectionForCurrentBaseProduct, collection => !!collection && !collection.isFetching && collection.expires === 0);
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Whether the review list of the current base product has to be requested again.
|
|
163
|
+
* Not memoized, because the result depends on the current time.
|
|
164
|
+
* @param state The current application state.
|
|
165
|
+
* @param props The product id and an optional variant id.
|
|
166
|
+
* @returns True when the list is missing, failed or expired, false while a request runs.
|
|
167
|
+
*/
|
|
168
|
+
export const isReviewListStale = (state, props) => {
|
|
169
|
+
const collection = getCollectionForCurrentBaseProduct(state, props);
|
|
170
|
+
return !collection || !collection.isFetching && (collection.expires ?? 0) <= Date.now();
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Whether the review list of the current base product is still loading.
|
|
175
|
+
* @param state The current application state.
|
|
176
|
+
* @returns True while a request runs or before the first response, unless the last request failed.
|
|
177
|
+
*/
|
|
178
|
+
export const isReviewListLoading = createSelector(getCollectionForCurrentBaseProduct, hasReviewListError, (collection, hasError) => !!collection?.isFetching || !collection?.reviews && !hasError);
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Retrieves the offset of the last review list request of the current base product.
|
|
182
|
+
* @param state The current application state.
|
|
183
|
+
* @returns The offset, or 0 when the list was not requested yet.
|
|
184
|
+
*/
|
|
185
|
+
export const getReviewListRequestOffset = createSelector(getCollectionForCurrentBaseProduct, collection => collection?.requestOffset ?? 0);
|
|
186
|
+
|
|
100
187
|
/**
|
|
101
188
|
* Select the user reviews state.
|
|
102
|
-
* @param
|
|
103
|
-
* @
|
|
189
|
+
* @param state The current application state.
|
|
190
|
+
* @returns The user reviews collection stored as productId => review.
|
|
104
191
|
*/
|
|
105
192
|
const getUserReviewsByProductId = createSelector(getReviewsState, state => state.userReviewsByProductId);
|
|
106
193
|
|
|
@@ -108,61 +195,85 @@ const getUserReviewsByProductId = createSelector(getReviewsState, state => state
|
|
|
108
195
|
* Retrieves a user review for a product.
|
|
109
196
|
*/
|
|
110
197
|
export const getUserReviewForProduct = createSelector(getUserReviewsByProductId, getReviews, (state, props = {}) => props.productId, (userReviews, allReviews, productId) => {
|
|
111
|
-
|
|
198
|
+
const userReview = userReviews && userReviews[productId];
|
|
199
|
+
if (!userReview || !allReviews[userReview.review]) {
|
|
112
200
|
return {};
|
|
113
201
|
}
|
|
114
202
|
return {
|
|
115
|
-
...allReviews[
|
|
203
|
+
...allReviews[userReview.review]
|
|
116
204
|
};
|
|
117
205
|
});
|
|
118
206
|
|
|
119
207
|
/**
|
|
120
208
|
* Gets user reviews fetching state. Only the first fetch is considered.
|
|
121
|
-
* @
|
|
209
|
+
* @returns True if user review for current product is being fetched.
|
|
122
210
|
*/
|
|
123
211
|
export const getUserReviewFirstFetchState = createSelector(getBaseProductId, getUserReviewsByProductId, (productId, userReviews) => !!(userReviews && productId && userReviews[productId] && !userReviews[productId].review && userReviews[productId].isFetching));
|
|
124
212
|
|
|
125
213
|
/**
|
|
126
214
|
* Get a user name for the review form.
|
|
127
|
-
* @param
|
|
128
|
-
* @returns
|
|
215
|
+
* @param state The state.
|
|
216
|
+
* @returns A user name.
|
|
129
217
|
*/
|
|
130
|
-
export const getDefaultAuthorName = state => isUserLoggedIn && state.user.data && state.user.data.firstName ? `${state.user.data.firstName} ${state.user.data.lastName}` : '';
|
|
218
|
+
export const getDefaultAuthorName = state => isUserLoggedIn(state) && state.user.data && state.user.data.firstName ? `${state.user.data.firstName} ${state.user.data.lastName}` : '';
|
|
131
219
|
|
|
132
220
|
/**
|
|
133
|
-
* Retrieves the current product reviews.
|
|
134
|
-
*
|
|
135
|
-
* @
|
|
136
|
-
* @return {Array|null} The reviews for a product.
|
|
221
|
+
* Retrieves the current product reviews in the order returned by the pipeline.
|
|
222
|
+
* @param state The current application state.
|
|
223
|
+
* @returns The reviews for a product.
|
|
137
224
|
*/
|
|
138
|
-
export const getProductReviews = createSelector(getCollectionForCurrentBaseProduct, getReviews,
|
|
225
|
+
export const getProductReviews = createSelector(getCollectionForCurrentBaseProduct, getReviews, (collection, allReviews) => {
|
|
139
226
|
if (!collection || !collection.reviews) {
|
|
140
227
|
return [];
|
|
141
228
|
}
|
|
142
|
-
|
|
143
|
-
// There is no user review. Returning only from reviews collection.
|
|
144
|
-
if (!userReview.id) {
|
|
145
|
-
return reviews;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// User review always on top. Avoid duplicates.
|
|
149
|
-
return [userReview].concat(reviews.filter(r => r.id !== userReview.id));
|
|
229
|
+
return collection.reviews.map(id => allReviews[id]);
|
|
150
230
|
});
|
|
151
231
|
|
|
152
232
|
/**
|
|
153
|
-
* Retrieves the current product reviews excerpt.
|
|
154
|
-
*
|
|
155
|
-
* @
|
|
156
|
-
* @return {Array|null} The reviews for a product
|
|
233
|
+
* Retrieves the current product reviews excerpt in the order returned by the pipeline.
|
|
234
|
+
* @param state The current application state.
|
|
235
|
+
* @returns The reviews for a product
|
|
157
236
|
*/
|
|
158
|
-
export const getProductReviewsExcerpt = createSelector(getBaseProductId, getProductReviewsExcerptState, getReviews,
|
|
237
|
+
export const getProductReviewsExcerpt = createSelector(getBaseProductId, getProductReviewsExcerptState, getReviews, (productId, productReviewsState, reviewsState) => {
|
|
159
238
|
const collection = productReviewsState[productId];
|
|
160
239
|
if (!collection || !collection.reviews) {
|
|
161
240
|
return null;
|
|
162
241
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
242
|
+
return collection.reviews.map(id => reviewsState[id]);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Retrieves the review preview collection of the current base product.
|
|
247
|
+
* @param state The current application state.
|
|
248
|
+
* @returns The collection, or null when the preview was not requested yet.
|
|
249
|
+
*/
|
|
250
|
+
const getProductReviewsExcerptCollection = createSelector(getBaseProductId, getProductReviewsExcerptState, (productId, productReviewsState) => productReviewsState[productId] || null);
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Whether the review preview of the current base product was not requested yet.
|
|
254
|
+
* @param state The current application state.
|
|
255
|
+
* @returns True when no preview collection exists.
|
|
256
|
+
*/
|
|
257
|
+
export const isProductReviewsExcerptMissing = createSelector(getProductReviewsExcerptCollection, collection => collection === null);
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Whether the last review preview request of the current base product failed before any
|
|
261
|
+
* reviews were received.
|
|
262
|
+
* @param state The current application state.
|
|
263
|
+
* @returns True when the preview request failed.
|
|
264
|
+
*/
|
|
265
|
+
export const hasProductReviewsExcerptError = createSelector(getProductReviewsExcerptCollection, collection => !!collection && !collection.isFetching && !collection.reviews && collection.requestId !== undefined);
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Whether the review preview of the current base product is still loading.
|
|
269
|
+
* @param state The current application state.
|
|
270
|
+
* @returns True while a request runs or before the first response, unless the last request failed.
|
|
271
|
+
*/
|
|
272
|
+
export const isProductReviewsExcerptLoading = createSelector(getProductReviewsExcerptCollection, hasProductReviewsExcerptError, (collection, hasError) => !!collection?.isFetching || !collection?.reviews && !hasError);
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Whether the review preview of the current base product is requested without stored reviews.
|
|
276
|
+
* @param state The current application state.
|
|
277
|
+
* @returns True while a request runs and no response was stored yet; false for a refresh.
|
|
278
|
+
*/
|
|
279
|
+
export const isProductReviewsExcerptPending = createSelector(getProductReviewsExcerptCollection, collection => !!collection?.isFetching && !collection.reviews);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReviewId, ReviewVote, OwnReviewVotesState } from '../types/reviews';
|
|
2
|
+
/**
|
|
3
|
+
* Selects the vote the user of this device gave for a review.
|
|
4
|
+
* @param state The application state.
|
|
5
|
+
* @param reviewId The ID of the review.
|
|
6
|
+
* @returns The vote, or null when the user did not vote on the review.
|
|
7
|
+
*/
|
|
8
|
+
export declare const getOwnReviewVote: (state: OwnReviewVotesState, reviewId: ReviewId) => ReviewVote | null;
|
|
9
|
+
//# sourceMappingURL=ownReviewVotes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownReviewVotes.d.ts","sourceRoot":"","sources":["../../../reviews/selectors/ownReviewVotes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAElF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,OAAO,mBAAmB,EAC1B,UAAU,QAAQ,KACjB,UAAU,GAAG,IAEf,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selects the vote the user of this device gave for a review.
|
|
3
|
+
* @param state The application state.
|
|
4
|
+
* @param reviewId The ID of the review.
|
|
5
|
+
* @returns The vote, or null when the user did not vote on the review.
|
|
6
|
+
*/
|
|
7
|
+
export const getOwnReviewVote = (state, reviewId) => state?.ownReviewVotes?.[String(reviewId)] ?? null;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ReviewFilterOption } from '../types/reviews';
|
|
2
|
+
import type { ReviewPaginationType, ReviewSettingsSliceState, ReviewSettingsState } from '../types/reviewSettings';
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves the review settings slice, falling back to an empty slice when absent.
|
|
5
|
+
* @param state The application state.
|
|
6
|
+
* @returns The review settings slice.
|
|
7
|
+
*/
|
|
8
|
+
export declare const getReviewSettingsState: (state: ReviewSettingsState) => ReviewSettingsSliceState;
|
|
9
|
+
export declare const getReviewFeatures: ((state: ReviewSettingsState) => string[]) & import("reselect").OutputSelectorFields<(args_0: ReviewSettingsSliceState) => string[], {
|
|
10
|
+
clearCache: () => void;
|
|
11
|
+
}> & {
|
|
12
|
+
clearCache: () => void;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Selects the pagination mode from the settings only. Returns `undefined` while unknown;
|
|
16
|
+
* never derived from `features` and never defaulted to offset.
|
|
17
|
+
*/
|
|
18
|
+
export declare const getReviewPaginationType: ((state: ReviewSettingsState) => ReviewPaginationType | undefined) & import("reselect").OutputSelectorFields<(args_0: ReviewSettingsSliceState) => ReviewPaginationType | undefined, {
|
|
19
|
+
clearCache: () => void;
|
|
20
|
+
}> & {
|
|
21
|
+
clearCache: () => void;
|
|
22
|
+
};
|
|
23
|
+
export declare const getReviewCustomFields: ((state: ReviewSettingsState) => unknown[]) & import("reselect").OutputSelectorFields<(args_0: ReviewSettingsSliceState) => unknown[], {
|
|
24
|
+
clearCache: () => void;
|
|
25
|
+
}> & {
|
|
26
|
+
clearCache: () => void;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Selects the sort values the provider supports, limited to the sort values the PWA knows
|
|
30
|
+
* and kept in the provider's order.
|
|
31
|
+
*/
|
|
32
|
+
export declare const getReviewSortOptions: ((state: ReviewSettingsState) => string[]) & import("reselect").OutputSelectorFields<(args_0: ReviewSettingsSliceState) => string[], {
|
|
33
|
+
clearCache: () => void;
|
|
34
|
+
}> & {
|
|
35
|
+
clearCache: () => void;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Selects the list filters the provider supports, in the order the PWA defines them.
|
|
39
|
+
*/
|
|
40
|
+
export declare const getReviewFilterOptions: ((state: ReviewSettingsState) => ReviewFilterOption[]) & import("reselect").OutputSelectorFields<(args_0: string[]) => ReviewFilterOption[], {
|
|
41
|
+
clearCache: () => void;
|
|
42
|
+
}> & {
|
|
43
|
+
clearCache: () => void;
|
|
44
|
+
};
|
|
45
|
+
export declare const isFetchingReviewSettings: ((state: ReviewSettingsState) => boolean) & import("reselect").OutputSelectorFields<(args_0: ReviewSettingsSliceState) => boolean, {
|
|
46
|
+
clearCache: () => void;
|
|
47
|
+
}> & {
|
|
48
|
+
clearCache: () => void;
|
|
49
|
+
};
|
|
50
|
+
export declare const isReviewCursorPagination: ((state: ReviewSettingsState) => boolean) & import("reselect").OutputSelectorFields<(args_0: ReviewPaginationType | undefined) => boolean, {
|
|
51
|
+
clearCache: () => void;
|
|
52
|
+
}> & {
|
|
53
|
+
clearCache: () => void;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Whether the active provider reports the given capability. A capability missing from the
|
|
57
|
+
* settings enables nothing.
|
|
58
|
+
* @param state The application state.
|
|
59
|
+
* @param feature The capability identifier to check.
|
|
60
|
+
* @returns Whether the capability is enabled.
|
|
61
|
+
*/
|
|
62
|
+
export declare const hasReviewFeature: (state: ReviewSettingsState, feature: string) => boolean;
|
|
63
|
+
//# sourceMappingURL=reviewSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewSettings.d.ts","sourceRoot":"","sources":["../../../reviews/selectors/reviewSettings.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EACV,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AAIjC;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,mBAAmB,KAAG,wBAClB,CAAC;AAEnD,eAAO,MAAM,iBAAiB;;;;CAG7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB;;;;CAGnC,CAAC;AAEF,eAAO,MAAM,qBAAqB;;;;CAGjC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;CAKhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;CAIlC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;CAGpC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;CAGpC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,mBAAmB,EAAE,SAAS,MAAM,KAAG,OACnC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createSelector } from 'reselect';
|
|
2
|
+
import { PAGINATION_TYPE_CURSOR, REVIEW_FILTERS, REVIEW_SORT_OPTIONS } from "../constants";
|
|
3
|
+
const EMPTY_SETTINGS = {};
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Retrieves the review settings slice, falling back to an empty slice when absent.
|
|
7
|
+
* @param state The application state.
|
|
8
|
+
* @returns The review settings slice.
|
|
9
|
+
*/
|
|
10
|
+
export const getReviewSettingsState = state => state?.reviews?.reviewSettings ?? EMPTY_SETTINGS;
|
|
11
|
+
export const getReviewFeatures = createSelector(getReviewSettingsState, settings => settings.features ?? []);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Selects the pagination mode from the settings only. Returns `undefined` while unknown;
|
|
15
|
+
* never derived from `features` and never defaulted to offset.
|
|
16
|
+
*/
|
|
17
|
+
export const getReviewPaginationType = createSelector(getReviewSettingsState, settings => settings.paginationType);
|
|
18
|
+
export const getReviewCustomFields = createSelector(getReviewSettingsState, settings => settings.customFields ?? []);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Selects the sort values the provider supports, limited to the sort values the PWA knows
|
|
22
|
+
* and kept in the provider's order.
|
|
23
|
+
*/
|
|
24
|
+
export const getReviewSortOptions = createSelector(getReviewSettingsState, settings => Array.isArray(settings.sortOptions) ? settings.sortOptions.filter(option => REVIEW_SORT_OPTIONS.includes(option)) : []);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Selects the list filters the provider supports, in the order the PWA defines them.
|
|
28
|
+
*/
|
|
29
|
+
export const getReviewFilterOptions = createSelector(getReviewFeatures, features => REVIEW_FILTERS.filter(filter => features.includes(filter.param)));
|
|
30
|
+
export const isFetchingReviewSettings = createSelector(getReviewSettingsState, settings => settings.isFetching ?? false);
|
|
31
|
+
export const isReviewCursorPagination = createSelector(getReviewPaginationType, paginationType => paginationType === PAGINATION_TYPE_CURSOR);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether the active provider reports the given capability. A capability missing from the
|
|
35
|
+
* settings enables nothing.
|
|
36
|
+
* @param state The application state.
|
|
37
|
+
* @param feature The capability identifier to check.
|
|
38
|
+
* @returns Whether the capability is enabled.
|
|
39
|
+
*/
|
|
40
|
+
export const hasReviewFeature = (state, feature) => getReviewFeatures(state).includes(feature);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReviewsProductProps, ReviewsSliceState } from '../types/reviews';
|
|
2
|
+
import type { ReviewSummary } from '../types/reviewSummary';
|
|
3
|
+
type SummaryState = {
|
|
4
|
+
product: unknown;
|
|
5
|
+
reviews?: Partial<ReviewsSliceState>;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Selects the review summary of a product. A summary delivered by the review provider wins.
|
|
9
|
+
* Without one the product data is the source, unless the provider reports that it delivers
|
|
10
|
+
* summaries: then the product data describes another dataset and is not used.
|
|
11
|
+
* @param state The application state.
|
|
12
|
+
* @param props The product id and an optional variant id, which takes precedence for the
|
|
13
|
+
* product data. Provider summaries are stored by the product id.
|
|
14
|
+
* @returns The summary, or null when none is available.
|
|
15
|
+
*/
|
|
16
|
+
export declare const getReviewSummary: (state: SummaryState, props?: ReviewsProductProps) => ReviewSummary | null;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=reviewSummary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewSummary.d.ts","sourceRoot":"","sources":["../../../reviews/selectors/reviewSummary.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACtC,CAAC;AAsCF;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,YAAY,EAAE,QAAO,mBAAwB,yBAcpF,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createSelector } from 'reselect';
|
|
2
|
+
import { getProductRating as getProductRatingSelector } from "../../product/selectors/product";
|
|
3
|
+
import { REVIEW_FEATURE_RATING_SUMMARY } from "../constants";
|
|
4
|
+
import { hasReviewFeature } from "./reviewSettings";
|
|
5
|
+
const getProductRating = getProductRatingSelector;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Normalizes a raw rating value.
|
|
9
|
+
* @param value A raw rating value from the product data.
|
|
10
|
+
* @returns The value when it is a finite number, otherwise null.
|
|
11
|
+
*/
|
|
12
|
+
const toFiniteNumber = value => typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Selects the review summary of a product from its product data.
|
|
16
|
+
*/
|
|
17
|
+
const getProductReviewSummary = createSelector(getProductRating, rating => {
|
|
18
|
+
if (!rating) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
average: toFiniteNumber(rating.average),
|
|
23
|
+
count: toFiniteNumber(rating.count)
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Selects the review summary of a product. A summary delivered by the review provider wins.
|
|
29
|
+
* Without one the product data is the source, unless the provider reports that it delivers
|
|
30
|
+
* summaries: then the product data describes another dataset and is not used.
|
|
31
|
+
* @param state The application state.
|
|
32
|
+
* @param props The product id and an optional variant id, which takes precedence for the
|
|
33
|
+
* product data. Provider summaries are stored by the product id.
|
|
34
|
+
* @returns The summary, or null when none is available.
|
|
35
|
+
*/
|
|
36
|
+
export const getReviewSummary = (state, props = {}) => {
|
|
37
|
+
const providerSummary = props.productId ? state.reviews?.reviewSummariesByProductId?.[props.productId] : undefined;
|
|
38
|
+
if (providerSummary) {
|
|
39
|
+
return providerSummary;
|
|
40
|
+
}
|
|
41
|
+
if (hasReviewFeature(state, REVIEW_FEATURE_RATING_SUMMARY)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return getProductReviewSummary(state, props);
|
|
45
|
+
};
|
package/reviews/streams/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { main$ } from '@shopgate/pwa-common/streams/main';
|
|
2
|
+
import { RESET_APP } from '@shopgate/pwa-common/constants/ActionTypes';
|
|
3
|
+
import { RESET_APP_REDUCERS } from '@shopgate/pwa-common/constants/Configuration';
|
|
4
|
+
import configuration from '@shopgate/pwa-common/collections/Configuration';
|
|
2
5
|
import { routeWillEnter$, routeWillLeave$ } from '@shopgate/pwa-common/streams/router';
|
|
3
6
|
import { ITEM_PATH, RECEIVE_PRODUCT, RECEIVE_PRODUCT_CACHED } from '@shopgate/pwa-common-commerce/product/constants';
|
|
4
7
|
import { REQUEST_SUBMIT_REVIEW, RECEIVE_SUBMIT_REVIEW, ERROR_SUBMIT_REVIEW, RESET_SUBMIT_REVIEW } from "../constants";
|
|
@@ -42,4 +45,19 @@ export const errorReviewSubmit$ = main$.filter(({
|
|
|
42
45
|
}) => [ERROR_SUBMIT_REVIEW, RESET_SUBMIT_REVIEW].includes(action.type));
|
|
43
46
|
export const shouldFetchReviews$ = main$.filter(({
|
|
44
47
|
action
|
|
45
|
-
}) => action.type === RECEIVE_PRODUCT || action.type === RECEIVE_PRODUCT_CACHED).merge(successReviewSubmit$);
|
|
48
|
+
}) => action.type === RECEIVE_PRODUCT || action.type === RECEIVE_PRODUCT_CACHED).merge(successReviewSubmit$);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Gets triggered after an app reset cleared the reviews state.
|
|
52
|
+
* A reset without an explicit reducer list uses the configured reset reducers.
|
|
53
|
+
* @type {Observable}
|
|
54
|
+
*/
|
|
55
|
+
export const reviewsDidReset$ = main$.filter(({
|
|
56
|
+
action
|
|
57
|
+
}) => {
|
|
58
|
+
if (action.type !== RESET_APP) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const resetReducers = action.reducers || configuration.get(RESET_APP_REDUCERS);
|
|
62
|
+
return Array.isArray(resetReducers) && resetReducers.includes('reviews');
|
|
63
|
+
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import appConfig from '@shopgate/pwa-common/helpers/config';
|
|
2
|
+
import { appWillStart$ } from '@shopgate/engage/core/streams';
|
|
2
3
|
import fetchProductReviews from "../actions/fetchProductReviews";
|
|
4
|
+
import fetchProductReviewSettings from "../actions/fetchProductReviewSettings";
|
|
3
5
|
import { REVIEW_PREVIEW_COUNT } from "../constants";
|
|
4
|
-
import { shouldFetchReviews$ } from "../streams";
|
|
6
|
+
import { reviewsDidReset$, shouldFetchReviews$ } from "../streams";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Review subscriptions.
|
|
@@ -11,10 +13,21 @@ export default function product(subscribe) {
|
|
|
11
13
|
if (!appConfig.hasReviews) {
|
|
12
14
|
return;
|
|
13
15
|
}
|
|
16
|
+
subscribe(appWillStart$, ({
|
|
17
|
+
dispatch
|
|
18
|
+
}) => {
|
|
19
|
+
dispatch(fetchProductReviewSettings());
|
|
20
|
+
});
|
|
21
|
+
subscribe(reviewsDidReset$, ({
|
|
22
|
+
dispatch
|
|
23
|
+
}) => {
|
|
24
|
+
dispatch(fetchProductReviewSettings());
|
|
25
|
+
});
|
|
14
26
|
subscribe(shouldFetchReviews$, ({
|
|
15
27
|
action,
|
|
16
28
|
dispatch
|
|
17
29
|
}) => {
|
|
30
|
+
dispatch(fetchProductReviewSettings());
|
|
18
31
|
if (action.productData) {
|
|
19
32
|
const {
|
|
20
33
|
id,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type ReviewPaginationType = 'offset' | 'cursor';
|
|
2
|
+
/**
|
|
3
|
+
* Provider review capabilities returned by shopgate.catalog.getProductReviewSettings.v1.
|
|
4
|
+
*/
|
|
5
|
+
export interface ReviewSettings {
|
|
6
|
+
/** Optional capabilities the provider supports; the PWA only acts on identifiers it knows. */
|
|
7
|
+
features: string[];
|
|
8
|
+
/** Whether the review list paginates by offset or cursor. */
|
|
9
|
+
paginationType: ReviewPaginationType;
|
|
10
|
+
/** Provider custom-field definitions; not consumed for display in the first delivery. */
|
|
11
|
+
customFields: unknown[];
|
|
12
|
+
/** Sort values the provider supports for the review list; unknown values are ignored. */
|
|
13
|
+
sortOptions?: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The review settings redux slice: the loaded settings plus request bookkeeping.
|
|
17
|
+
* Empty before the first successful load, so every settings field is optional here.
|
|
18
|
+
*/
|
|
19
|
+
export interface ReviewSettingsSliceState extends Partial<ReviewSettings> {
|
|
20
|
+
isFetching?: boolean;
|
|
21
|
+
expires?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Minimal application state shape the review settings selectors read from.
|
|
25
|
+
*/
|
|
26
|
+
export interface ReviewSettingsState {
|
|
27
|
+
reviews?: {
|
|
28
|
+
reviewSettings?: ReviewSettingsSliceState;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=reviewSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewSettings.d.ts","sourceRoot":"","sources":["../../../reviews/types/reviewSettings.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,8FAA8F;IAC9F,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,6DAA6D;IAC7D,cAAc,EAAE,oBAAoB,CAAC;IACrC,yFAAyF;IACzF,YAAY,EAAE,OAAO,EAAE,CAAC;IACxB,yFAAyF;IACzF,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAyB,SAAQ,OAAO,CAAC,cAAc,CAAC;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE;QACR,cAAc,CAAC,EAAE,wBAAwB,CAAC;KAC3C,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The number of ratings per number of stars, from 5 to 1.
|
|
3
|
+
*/
|
|
4
|
+
export type ReviewRatingDistribution = Record<'5' | '4' | '3' | '2' | '1', number>;
|
|
5
|
+
/**
|
|
6
|
+
* The review summary of a product, from the review provider or from the product data.
|
|
7
|
+
*/
|
|
8
|
+
export interface ReviewSummary {
|
|
9
|
+
/** Average rating on the 0–100 scale; null when not provided. */
|
|
10
|
+
average: number | null;
|
|
11
|
+
/** Number of ratings incl. star-only ratings; differs from the list's totalReviewCount. */
|
|
12
|
+
count: number | null;
|
|
13
|
+
/** Only set when the review provider delivers a complete distribution. */
|
|
14
|
+
distribution?: ReviewRatingDistribution;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=reviewSummary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewSummary.d.ts","sourceRoot":"","sources":["../../../reviews/types/reviewSummary.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,MAAM,CAAC,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,2FAA2F;IAC3F,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,wBAAwB,CAAC;CACzC"}
|