@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.
Files changed (107) hide show
  1. package/category/constants/Portals.js +4 -0
  2. package/filter/actions/helpers/buildRequestFilters.d.ts +9 -0
  3. package/filter/actions/helpers/buildRequestFilters.d.ts.map +1 -0
  4. package/filter/constants/Pipelines.d.ts +2 -0
  5. package/filter/constants/Pipelines.d.ts.map +1 -0
  6. package/filter/selectors/index.d.ts +42 -0
  7. package/filter/selectors/index.d.ts.map +1 -0
  8. package/package.json +3 -3
  9. package/product/constants/Pipelines.d.ts +13 -0
  10. package/product/constants/Pipelines.d.ts.map +1 -0
  11. package/product/constants/index.d.ts +67 -0
  12. package/product/constants/index.d.ts.map +1 -0
  13. package/product/helpers/index.d.ts +5 -0
  14. package/product/helpers/index.d.ts.map +1 -0
  15. package/product/selectors/product.d.ts +513 -0
  16. package/product/selectors/product.d.ts.map +1 -0
  17. package/reviews/action-creators/errorProductReviews.d.ts +19 -0
  18. package/reviews/action-creators/errorProductReviews.d.ts.map +1 -0
  19. package/reviews/action-creators/errorProductReviews.js +5 -4
  20. package/reviews/action-creators/errorReviews.d.ts +19 -0
  21. package/reviews/action-creators/errorReviews.d.ts.map +1 -0
  22. package/reviews/action-creators/errorReviews.js +5 -4
  23. package/reviews/action-creators/receiveProductReviews.d.ts +25 -0
  24. package/reviews/action-creators/receiveProductReviews.d.ts.map +1 -0
  25. package/reviews/action-creators/receiveProductReviews.js +10 -7
  26. package/reviews/action-creators/receiveReviewVote.d.ts +18 -0
  27. package/reviews/action-creators/receiveReviewVote.d.ts.map +1 -0
  28. package/reviews/action-creators/receiveReviewVote.js +15 -0
  29. package/reviews/action-creators/receiveReviews.d.ts +29 -0
  30. package/reviews/action-creators/receiveReviews.d.ts.map +1 -0
  31. package/reviews/action-creators/receiveReviews.js +13 -8
  32. package/reviews/action-creators/requestProductReviews.d.ts +21 -0
  33. package/reviews/action-creators/requestProductReviews.d.ts.map +1 -0
  34. package/reviews/action-creators/requestProductReviews.js +6 -5
  35. package/reviews/action-creators/requestReviews.d.ts +19 -0
  36. package/reviews/action-creators/requestReviews.d.ts.map +1 -0
  37. package/reviews/action-creators/requestReviews.js +5 -4
  38. package/reviews/action-creators/reviewSettings.d.ts +31 -0
  39. package/reviews/action-creators/reviewSettings.d.ts.map +1 -0
  40. package/reviews/action-creators/reviewSettings.js +28 -0
  41. package/reviews/actions/fetchProductReviewSettings.d.ts +5 -0
  42. package/reviews/actions/fetchProductReviewSettings.d.ts.map +1 -0
  43. package/reviews/actions/fetchProductReviewSettings.js +25 -0
  44. package/reviews/actions/fetchProductReviews.d.ts +17 -0
  45. package/reviews/actions/fetchProductReviews.d.ts.map +1 -0
  46. package/reviews/actions/fetchProductReviews.js +17 -9
  47. package/reviews/actions/fetchReviews.d.ts +22 -0
  48. package/reviews/actions/fetchReviews.d.ts.map +1 -0
  49. package/reviews/actions/fetchReviews.js +48 -14
  50. package/reviews/actions/submitReviewVote.d.ts +15 -0
  51. package/reviews/actions/submitReviewVote.d.ts.map +1 -0
  52. package/reviews/actions/submitReviewVote.js +46 -0
  53. package/reviews/constants/Pipelines.d.ts +7 -0
  54. package/reviews/constants/Pipelines.d.ts.map +1 -0
  55. package/reviews/constants/Pipelines.js +3 -1
  56. package/reviews/constants/index.d.ts +47 -0
  57. package/reviews/constants/index.d.ts.map +1 -0
  58. package/reviews/constants/index.js +43 -1
  59. package/reviews/helpers/filters.d.ts +16 -0
  60. package/reviews/helpers/filters.d.ts.map +1 -0
  61. package/reviews/helpers/filters.js +36 -0
  62. package/reviews/helpers/summary.d.ts +8 -0
  63. package/reviews/helpers/summary.d.ts.map +1 -0
  64. package/reviews/helpers/summary.js +55 -0
  65. package/reviews/index.js +1 -0
  66. package/reviews/reducers/index.js +5 -1
  67. package/reviews/reducers/ownReviewVotes.d.ts +13 -0
  68. package/reviews/reducers/ownReviewVotes.d.ts.map +1 -0
  69. package/reviews/reducers/ownReviewVotes.js +23 -0
  70. package/reviews/reducers/reviewSettings.d.ts +13 -0
  71. package/reviews/reducers/reviewSettings.d.ts.map +1 -0
  72. package/reviews/reducers/reviewSettings.js +33 -0
  73. package/reviews/reducers/reviewSummariesByProductId.d.ts +18 -0
  74. package/reviews/reducers/reviewSummariesByProductId.d.ts.map +1 -0
  75. package/reviews/reducers/reviewSummariesByProductId.js +27 -0
  76. package/reviews/reducers/reviewsByHash.d.ts +25 -0
  77. package/reviews/reducers/reviewsByHash.d.ts.map +1 -0
  78. package/reviews/reducers/reviewsByHash.js +70 -27
  79. package/reviews/reducers/reviewsById.d.ts +20 -0
  80. package/reviews/reducers/reviewsById.d.ts.map +1 -0
  81. package/reviews/reducers/reviewsById.js +23 -7
  82. package/reviews/reducers/reviewsByProductId.d.ts +23 -0
  83. package/reviews/reducers/reviewsByProductId.d.ts.map +1 -0
  84. package/reviews/reducers/reviewsByProductId.js +38 -23
  85. package/reviews/selectors/index.d.ts +278 -0
  86. package/reviews/selectors/index.d.ts.map +1 -0
  87. package/reviews/selectors/index.js +167 -56
  88. package/reviews/selectors/ownReviewVotes.d.ts +9 -0
  89. package/reviews/selectors/ownReviewVotes.d.ts.map +1 -0
  90. package/reviews/selectors/ownReviewVotes.js +7 -0
  91. package/reviews/selectors/reviewSettings.d.ts +63 -0
  92. package/reviews/selectors/reviewSettings.d.ts.map +1 -0
  93. package/reviews/selectors/reviewSettings.js +40 -0
  94. package/reviews/selectors/reviewSummary.d.ts +18 -0
  95. package/reviews/selectors/reviewSummary.d.ts.map +1 -0
  96. package/reviews/selectors/reviewSummary.js +45 -0
  97. package/reviews/streams/index.js +19 -1
  98. package/reviews/subscriptions/index.js +14 -1
  99. package/reviews/types/reviewSettings.d.ts +31 -0
  100. package/reviews/types/reviewSettings.d.ts.map +1 -0
  101. package/reviews/types/reviewSettings.js +1 -0
  102. package/reviews/types/reviewSummary.d.ts +16 -0
  103. package/reviews/types/reviewSummary.d.ts.map +1 -0
  104. package/reviews/types/reviewSummary.js +1 -0
  105. package/reviews/types/reviews.d.ts +190 -0
  106. package/reviews/types/reviews.d.ts.map +1 -0
  107. package/reviews/types/reviews.js +1 -0
@@ -22,8 +22,50 @@ export const RECEIVE_SUBMIT_REVIEW = 'RECEIVE_SUBMIT_REVIEW';
22
22
  export const ERROR_SUBMIT_REVIEW = 'ERROR_SUBMIT_REVIEW';
23
23
  export const RESET_SUBMIT_REVIEW = 'RESET_SUBMIT_REVIEW';
24
24
 
25
+ // REVIEW VOTES
26
+ export const RECEIVE_REVIEW_VOTE = 'RECEIVE_REVIEW_VOTE';
27
+ export const REVIEW_FEATURE_VOTES = 'reviewVotes';
28
+
29
+ // REVIEW SUMMARY
30
+ export const REVIEW_FEATURE_RATING_SUMMARY = 'ratingSummary';
31
+
32
+ // REVIEW LIST QUERY
33
+ /**
34
+ * The list filters the PWA knows: the request parameter that activates the filter, which a
35
+ * provider also reports as capability in its settings, the kind of its control and the label.
36
+ * A toggle is sent as `true`, the rate filter as the number of stars from 1 to 5.
37
+ */
38
+ export const REVIEW_FILTERS = [{
39
+ param: 'filterMedia',
40
+ type: 'toggle',
41
+ label: 'reviews.filter_media'
42
+ }, {
43
+ param: 'filterVerified',
44
+ type: 'toggle',
45
+ label: 'reviews.filter_verified'
46
+ }, {
47
+ param: 'filterRate',
48
+ type: 'rate',
49
+ label: 'reviews.filter_rate_all'
50
+ }];
51
+ export const REVIEW_SORT_OPTIONS = ['relevance', 'dateDesc', 'dateAsc', 'rateDesc', 'rateAsc', 'helpfulDesc'];
52
+
53
+ // PRODUCT REVIEW SETTINGS
54
+ export const REVIEW_SETTINGS_LIFETIME = 60 * 60 * 1000;
55
+ export const REQUEST_PRODUCT_REVIEW_SETTINGS = 'REQUEST_PRODUCT_REVIEW_SETTINGS';
56
+ export const RECEIVE_PRODUCT_REVIEW_SETTINGS = 'RECEIVE_PRODUCT_REVIEW_SETTINGS';
57
+ export const ERROR_PRODUCT_REVIEW_SETTINGS = 'ERROR_PRODUCT_REVIEW_SETTINGS';
58
+ export const PAGINATION_TYPE_OFFSET = 'offset';
59
+ export const PAGINATION_TYPE_CURSOR = 'cursor';
60
+
25
61
  /**
26
62
  * Max number of reviews shown
27
63
  * @type {number}
28
64
  */
29
- export const REVIEW_PREVIEW_COUNT = 2;
65
+ export const REVIEW_PREVIEW_COUNT = 2;
66
+
67
+ /**
68
+ * Number of reviews loaded per request on the full review page.
69
+ * @type {number}
70
+ */
71
+ export const REVIEW_ITEMS_PER_PAGE = 10;
@@ -0,0 +1,16 @@
1
+ import type { ReviewListFilterInput, ReviewListFilters } from '../types/reviews';
2
+ /**
3
+ * Reduces filter values to the active filters. A toggle is active for any truthy value, the
4
+ * rate filter only for a whole number of stars from 1 to 5.
5
+ * @param filters Filter values by request parameter.
6
+ * @returns The active filters, or undefined when none is active.
7
+ */
8
+ export declare const getActiveReviewFilters: (filters?: ReviewListFilterInput | null) => ReviewListFilters | undefined;
9
+ /**
10
+ * Compares two sets of list filters.
11
+ * @param a Filter values by request parameter.
12
+ * @param b Filter values by request parameter.
13
+ * @returns Whether the same filters are active with the same values in both.
14
+ */
15
+ export declare const areReviewFiltersEqual: (a?: ReviewListFilterInput | null, b?: ReviewListFilterInput | null) => boolean;
16
+ //# sourceMappingURL=filters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../../reviews/helpers/filters.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,kBAAkB,CAAC;AAI1B;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GACjC,UAAU,qBAAqB,GAAG,IAAI,KACrC,iBAAiB,GAAG,SAgBtB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,IAAI,qBAAqB,GAAG,IAAI,EAChC,IAAI,qBAAqB,GAAG,IAAI,KAC/B,OAEF,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { REVIEW_FILTERS } from "../constants";
2
+ const FILTERS = REVIEW_FILTERS;
3
+
4
+ /**
5
+ * Reduces filter values to the active filters. A toggle is active for any truthy value, the
6
+ * rate filter only for a whole number of stars from 1 to 5.
7
+ * @param filters Filter values by request parameter.
8
+ * @returns The active filters, or undefined when none is active.
9
+ */
10
+ export const getActiveReviewFilters = filters => {
11
+ const active = {};
12
+ FILTERS.forEach(({
13
+ param,
14
+ type
15
+ }) => {
16
+ const value = filters?.[param];
17
+ if (type === 'rate') {
18
+ if (typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= 5) {
19
+ active.filterRate = value;
20
+ }
21
+ } else if (value && param !== 'filterRate') {
22
+ active[param] = true;
23
+ }
24
+ });
25
+ return Object.keys(active).length > 0 ? active : undefined;
26
+ };
27
+
28
+ /**
29
+ * Compares two sets of list filters.
30
+ * @param a Filter values by request parameter.
31
+ * @param b Filter values by request parameter.
32
+ * @returns Whether the same filters are active with the same values in both.
33
+ */
34
+ export const areReviewFiltersEqual = (a, b) => FILTERS.every(({
35
+ param
36
+ }) => (a?.[param] || undefined) === (b?.[param] || undefined));
@@ -0,0 +1,8 @@
1
+ import type { ReviewSummary } from '../types/reviewSummary';
2
+ /**
3
+ * Reduces the summary of a review list response to the review summary of the PWA.
4
+ * @param value The summary of a pipeline response.
5
+ * @returns The summary, or null when it has no numeric average.
6
+ */
7
+ export declare const normalizeReviewSummary: (value: unknown) => ReviewSummary | null;
8
+ //# sourceMappingURL=summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../../reviews/helpers/summary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAsCtF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,aAAa,GAAG,IAkBvE,CAAC"}
@@ -0,0 +1,55 @@
1
+ const STARS = ['5', '4', '3', '2', '1'];
2
+
3
+ /**
4
+ * @param value A value from a pipeline response.
5
+ * @returns Whether the value is a finite number.
6
+ */
7
+ const isFiniteNumber = value => typeof value === 'number' && Number.isFinite(value);
8
+
9
+ /**
10
+ * Reduces the distribution of a pipeline response to the counts per number of stars.
11
+ * @param value The distribution of a pipeline response.
12
+ * @returns The distribution, or undefined unless all five counts are numbers of at least 0.
13
+ */
14
+ const normalizeDistribution = value => {
15
+ if (!value || typeof value !== 'object') {
16
+ return undefined;
17
+ }
18
+ const counts = value;
19
+ const distribution = {};
20
+ for (let index = 0; index < STARS.length; index += 1) {
21
+ const count = counts[STARS[index]];
22
+ if (!isFiniteNumber(count) || count < 0) {
23
+ return undefined;
24
+ }
25
+ distribution[STARS[index]] = count;
26
+ }
27
+ return distribution;
28
+ };
29
+
30
+ /**
31
+ * Reduces the summary of a review list response to the review summary of the PWA.
32
+ * @param value The summary of a pipeline response.
33
+ * @returns The summary, or null when it has no numeric average.
34
+ */
35
+ export const normalizeReviewSummary = value => {
36
+ if (!value || typeof value !== 'object') {
37
+ return null;
38
+ }
39
+ const {
40
+ average,
41
+ count,
42
+ distribution
43
+ } = value;
44
+ if (!isFiniteNumber(average)) {
45
+ return null;
46
+ }
47
+ const normalizedDistribution = normalizeDistribution(distribution);
48
+ return {
49
+ average,
50
+ count: isFiniteNumber(count) && count >= 0 ? count : null,
51
+ ...(normalizedDistribution && {
52
+ distribution: normalizedDistribution
53
+ })
54
+ };
55
+ };
package/reviews/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // ACTIONS
2
2
  export { default as fetchProductReviews } from "./actions/fetchProductReviews";
3
3
  export { default as fetchReviews } from "./actions/fetchReviews";
4
+ export { default as fetchProductReviewSettings } from "./actions/fetchProductReviewSettings";
4
5
  export { default as fetchUserReview } from "./actions/fetchUserReview";
5
6
  export { default as flushUserReview } from "./actions/flushUserReview";
6
7
  export { default as submitReview } from "./actions/submitReview";
@@ -3,9 +3,13 @@ import reviewsByHash from "./reviewsByHash";
3
3
  import reviewsById from "./reviewsById";
4
4
  import reviewsByProductId from "./reviewsByProductId";
5
5
  import userReviewsByProductId from "./userReviewsByProductId";
6
+ import reviewSettings from "./reviewSettings";
7
+ import reviewSummariesByProductId from "./reviewSummariesByProductId";
6
8
  export default combineReducers({
7
9
  reviewsByHash,
8
10
  reviewsById,
9
11
  reviewsByProductId,
10
- userReviewsByProductId
12
+ userReviewsByProductId,
13
+ reviewSettings,
14
+ reviewSummariesByProductId
11
15
  });
@@ -0,0 +1,13 @@
1
+ import type { Reducer, UnknownAction } from 'redux';
2
+ import type { ReceiveReviewVoteAction } from '../action-creators/receiveReviewVote';
3
+ import type { OwnReviewVotes } from '../types/reviews';
4
+ type OwnReviewVotesAction = ReceiveReviewVoteAction | UnknownAction;
5
+ /**
6
+ * Stores the votes the user of this device gave by review id.
7
+ * @param state The current state.
8
+ * @param action The action object.
9
+ * @returns The new state.
10
+ */
11
+ declare const ownReviewVotes: Reducer<OwnReviewVotes, OwnReviewVotesAction>;
12
+ export default ownReviewVotes;
13
+ //# sourceMappingURL=ownReviewVotes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownReviewVotes.d.ts","sourceRoot":"","sources":["../../../reviews/reducers/ownReviewVotes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,KAAK,oBAAoB,GAAG,uBAAuB,GAAG,aAAa,CAAC;AAEpE;;;;;GAKG;AACH,QAAA,MAAM,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,oBAAoB,CAcjE,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { RECEIVE_REVIEW_VOTE } from "../constants";
2
+ /**
3
+ * Stores the votes the user of this device gave by review id.
4
+ * @param state The current state.
5
+ * @param action The action object.
6
+ * @returns The new state.
7
+ */
8
+ const ownReviewVotes = (state = {}, action = {
9
+ type: ''
10
+ }) => {
11
+ if (action.type !== RECEIVE_REVIEW_VOTE) {
12
+ return state;
13
+ }
14
+ const {
15
+ reviewId,
16
+ vote
17
+ } = action;
18
+ return {
19
+ ...state,
20
+ [String(reviewId)]: vote
21
+ };
22
+ };
23
+ export default ownReviewVotes;
@@ -0,0 +1,13 @@
1
+ import type { Reducer } from 'redux';
2
+ import type { RequestProductReviewSettingsAction, ReceiveProductReviewSettingsAction, ErrorProductReviewSettingsAction } from '../action-creators/reviewSettings';
3
+ import type { ReviewSettingsSliceState } from '../types/reviewSettings';
4
+ type ReviewSettingsAction = RequestProductReviewSettingsAction | ReceiveProductReviewSettingsAction | ErrorProductReviewSettingsAction;
5
+ /**
6
+ * Stores the product review settings with request bookkeeping.
7
+ * @param state The current state.
8
+ * @param action The action object.
9
+ * @returns The new state.
10
+ */
11
+ declare const reviewSettings: Reducer<ReviewSettingsSliceState, ReviewSettingsAction>;
12
+ export default reviewSettings;
13
+ //# sourceMappingURL=reviewSettings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewSettings.d.ts","sourceRoot":"","sources":["../../../reviews/reducers/reviewSettings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAOrC,OAAO,KAAK,EACV,kCAAkC,EAClC,kCAAkC,EAClC,gCAAgC,EACjC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAExE,KAAK,oBAAoB,GACrB,kCAAkC,GAClC,kCAAkC,GAClC,gCAAgC,CAAC;AAErC;;;;;GAKG;AACH,QAAA,MAAM,cAAc,EAAE,OAAO,CAAC,wBAAwB,EAAE,oBAAoB,CA2B3E,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { REQUEST_PRODUCT_REVIEW_SETTINGS, RECEIVE_PRODUCT_REVIEW_SETTINGS, ERROR_PRODUCT_REVIEW_SETTINGS, REVIEW_SETTINGS_LIFETIME } from "../constants";
2
+ /**
3
+ * Stores the product review settings with request bookkeeping.
4
+ * @param state The current state.
5
+ * @param action The action object.
6
+ * @returns The new state.
7
+ */
8
+ const reviewSettings = (state = {}, action = {}) => {
9
+ switch (action.type) {
10
+ case REQUEST_PRODUCT_REVIEW_SETTINGS:
11
+ return {
12
+ ...state,
13
+ isFetching: true,
14
+ expires: 0
15
+ };
16
+ case RECEIVE_PRODUCT_REVIEW_SETTINGS:
17
+ return {
18
+ ...state,
19
+ ...action.settings,
20
+ isFetching: false,
21
+ expires: Date.now() + REVIEW_SETTINGS_LIFETIME
22
+ };
23
+ case ERROR_PRODUCT_REVIEW_SETTINGS:
24
+ return {
25
+ ...state,
26
+ isFetching: false,
27
+ expires: 0
28
+ };
29
+ default:
30
+ return state;
31
+ }
32
+ };
33
+ export default reviewSettings;
@@ -0,0 +1,18 @@
1
+ import type { Reducer, UnknownAction } from 'redux';
2
+ import type { ReviewSummary } from '../types/reviewSummary';
3
+ type ReviewSummariesByProductId = Record<string, ReviewSummary>;
4
+ type ReceiveWithSummaryAction = UnknownAction & {
5
+ productId?: string;
6
+ summary?: unknown;
7
+ };
8
+ /**
9
+ * Stores the rating summary a review provider delivers with a review list, by the product id
10
+ * the list was requested for. The last response with a valid summary wins; a response without
11
+ * one, or with the same numbers, keeps the stored summary.
12
+ * @param state The current state.
13
+ * @param action The action object.
14
+ * @returns The new state.
15
+ */
16
+ declare const reviewSummariesByProductId: Reducer<ReviewSummariesByProductId, ReceiveWithSummaryAction>;
17
+ export default reviewSummariesByProductId;
18
+ //# sourceMappingURL=reviewSummariesByProductId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewSummariesByProductId.d.ts","sourceRoot":"","sources":["../../../reviews/reducers/reviewSummariesByProductId.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,KAAK,0BAA0B,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAEhE,KAAK,wBAAwB,GAAG,aAAa,GAAG;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,QAAA,MAAM,0BAA0B,EAAE,OAAO,CAAC,0BAA0B,EAAE,wBAAwB,CAkB7F,CAAC;AAEF,eAAe,0BAA0B,CAAC"}
@@ -0,0 +1,27 @@
1
+ import isEqual from 'lodash/isEqual';
2
+ import { RECEIVE_PRODUCT_REVIEWS, RECEIVE_REVIEWS } from "../constants";
3
+ import { normalizeReviewSummary } from "../helpers/summary";
4
+ /**
5
+ * Stores the rating summary a review provider delivers with a review list, by the product id
6
+ * the list was requested for. The last response with a valid summary wins; a response without
7
+ * one, or with the same numbers, keeps the stored summary.
8
+ * @param state The current state.
9
+ * @param action The action object.
10
+ * @returns The new state.
11
+ */
12
+ const reviewSummariesByProductId = (state = {}, action = {
13
+ type: ''
14
+ }) => {
15
+ if (action.type !== RECEIVE_PRODUCT_REVIEWS && action.type !== RECEIVE_REVIEWS) {
16
+ return state;
17
+ }
18
+ const summary = normalizeReviewSummary(action.summary);
19
+ if (!summary || !action.productId || isEqual(state[action.productId], summary)) {
20
+ return state;
21
+ }
22
+ return {
23
+ ...state,
24
+ [action.productId]: summary
25
+ };
26
+ };
27
+ export default reviewSummariesByProductId;
@@ -0,0 +1,25 @@
1
+ import type { Reducer } from 'redux';
2
+ import { RECEIVE_SUBMIT_REVIEW } from '../constants';
3
+ import type { RequestReviewsAction } from '../action-creators/requestReviews';
4
+ import type { ReceiveReviewsAction } from '../action-creators/receiveReviews';
5
+ import type { ErrorReviewsAction } from '../action-creators/errorReviews';
6
+ import type { ReviewsByHash } from '../types/reviews';
7
+ type ReceiveSubmitReviewAction = {
8
+ type: typeof RECEIVE_SUBMIT_REVIEW;
9
+ review: {
10
+ productId: string;
11
+ };
12
+ };
13
+ type ReviewsByHashAction = RequestReviewsAction | ReceiveReviewsAction | ErrorReviewsAction | ReceiveSubmitReviewAction;
14
+ /**
15
+ * Stores a collection of products by the related hash of the request parameters.
16
+ * Responses are only applied when they belong to the latest request of a collection.
17
+ * A first page replaces the collection, later pages are only appended for the same sort and
18
+ * filter. A submitted review expires the list of its product without marking it as failed.
19
+ * @param state The current state.
20
+ * @param action The current redux action.
21
+ * @returns The new state.
22
+ */
23
+ declare const reviewsByHash: Reducer<ReviewsByHash, ReviewsByHashAction>;
24
+ export default reviewsByHash;
25
+ //# sourceMappingURL=reviewsByHash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewsByHash.d.ts","sourceRoot":"","sources":["../../../reviews/reducers/reviewsByHash.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAErC,OAAO,EAKL,qBAAqB,EACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,OAAO,qBAAqB,CAAC;IACnC,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,KAAK,mBAAmB,GACpB,oBAAoB,GACpB,oBAAoB,GACpB,kBAAkB,GAClB,yBAAyB,CAAC;AAE9B;;;;;;;;GAQG;AACH,QAAA,MAAM,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,mBAAmB,CAiG9D,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -1,13 +1,18 @@
1
1
  import uniq from 'lodash/uniq';
2
- import { REVIEWS_LIFETIME, REQUEST_REVIEWS, RECEIVE_REVIEWS, ERROR_REVIEWS } from "../constants";
3
-
2
+ import { generateResultHash } from '@shopgate/pwa-common/helpers/redux';
3
+ import { REVIEWS_LIFETIME, REQUEST_REVIEWS, RECEIVE_REVIEWS, ERROR_REVIEWS, RECEIVE_SUBMIT_REVIEW } from "../constants";
4
+ import { SHOPGATE_CATALOG_GET_PRODUCT_REVIEWS } from "../constants/Pipelines";
5
+ import { areReviewFiltersEqual } from "../helpers/filters";
4
6
  /**
5
7
  * Stores a collection of products by the related hash of the request parameters.
6
- * @param {Object} [state={}] The current state.
7
- * @param {Object} action The current redux action.
8
- * @return {Object} The new state.
8
+ * Responses are only applied when they belong to the latest request of a collection.
9
+ * A first page replaces the collection, later pages are only appended for the same sort and
10
+ * filter. A submitted review expires the list of its product without marking it as failed.
11
+ * @param state The current state.
12
+ * @param action The current redux action.
13
+ * @returns The new state.
9
14
  */
10
- function reviewsByHash(state = {}, action = {}) {
15
+ const reviewsByHash = (state = {}, action = {}) => {
11
16
  switch (action.type) {
12
17
  case REQUEST_REVIEWS:
13
18
  return {
@@ -15,42 +20,80 @@ function reviewsByHash(state = {}, action = {}) {
15
20
  [action.hash]: {
16
21
  ...state[action.hash],
17
22
  isFetching: true,
18
- expires: 0
23
+ expires: 0,
24
+ requestId: action.requestId,
25
+ requestOffset: action.offset,
26
+ requestSort: action.sort,
27
+ requestFilters: action.filters
19
28
  }
20
29
  };
21
30
  case RECEIVE_REVIEWS:
22
31
  {
23
- const reviews = state[action.hash].reviews || [];
24
- const nextReviews = action.reviews || [];
25
-
26
- /**
27
- * If there are no previous reviews and no incoming reviews
28
- * its set to empty array, otherwise it will be an array of the previous and the
29
- * new reviews. Duplicates are removed.
30
- */
31
- const stateReviews = reviews || nextReviews.length ? uniq([].concat(reviews, nextReviews.map(review => review.id))) : [];
32
+ const collection = state[action.hash];
33
+ if (!collection || collection.requestId !== action.requestId) {
34
+ return state;
35
+ }
36
+ const nextReviewIds = (action.reviews || []).map(review => review.id);
37
+ const isFirstPage = action.offset === 0;
38
+ const isSameQuery = collection.sort === action.sort && areReviewFiltersEqual(collection.filters, action.filters);
39
+ if (!isFirstPage && !isSameQuery) {
40
+ return {
41
+ ...state,
42
+ [action.hash]: {
43
+ ...collection,
44
+ isFetching: false,
45
+ expires: collection.reviews ? Date.now() + REVIEWS_LIFETIME : 0
46
+ }
47
+ };
48
+ }
32
49
  return {
33
50
  ...state,
34
51
  [action.hash]: {
35
- ...state[action.hash],
36
- reviews: stateReviews,
37
- totalReviewCount: action.totalReviewCount || null,
52
+ ...collection,
53
+ reviews: isFirstPage ? uniq(nextReviewIds) : uniq([].concat(collection.reviews || [], nextReviewIds)),
54
+ sort: action.sort,
55
+ filters: action.filters,
56
+ totalReviewCount: typeof action.totalReviewCount === 'number' ? action.totalReviewCount : null,
57
+ after: action.after || null,
38
58
  isFetching: false,
39
59
  expires: Date.now() + REVIEWS_LIFETIME
40
60
  }
41
61
  };
42
62
  }
43
63
  case ERROR_REVIEWS:
44
- return {
45
- ...state,
46
- [action.hash]: {
47
- ...state[action.hash],
48
- isFetching: false,
49
- expires: 0
64
+ {
65
+ const collection = state[action.hash];
66
+ if (!collection || collection.requestId !== action.requestId) {
67
+ return state;
50
68
  }
51
- };
69
+ return {
70
+ ...state,
71
+ [action.hash]: {
72
+ ...collection,
73
+ isFetching: false,
74
+ expires: 0
75
+ }
76
+ };
77
+ }
78
+ case RECEIVE_SUBMIT_REVIEW:
79
+ {
80
+ const hash = generateResultHash({
81
+ pipeline: SHOPGATE_CATALOG_GET_PRODUCT_REVIEWS,
82
+ productId: action.review.productId
83
+ }, false);
84
+ if (!state[hash]) {
85
+ return state;
86
+ }
87
+ return {
88
+ ...state,
89
+ [hash]: {
90
+ ...state[hash],
91
+ expires: Date.now()
92
+ }
93
+ };
94
+ }
52
95
  default:
53
96
  return state;
54
97
  }
55
- }
98
+ };
56
99
  export default reviewsByHash;
@@ -0,0 +1,20 @@
1
+ import type { Reducer } from 'redux';
2
+ import { RECEIVE_USER_REVIEW, RECEIVE_SUBMIT_REVIEW } from '../constants';
3
+ import type { ReceiveProductReviewsAction } from '../action-creators/receiveProductReviews';
4
+ import type { ReceiveReviewsAction } from '../action-creators/receiveReviews';
5
+ import type { ReceiveReviewVoteAction } from '../action-creators/receiveReviewVote';
6
+ import type { Review, ReviewsById } from '../types/reviews';
7
+ type ReceiveSingleReviewAction = {
8
+ type: typeof RECEIVE_SUBMIT_REVIEW | typeof RECEIVE_USER_REVIEW;
9
+ review?: Partial<Review>;
10
+ };
11
+ type ReviewsByIdAction = ReceiveProductReviewsAction | ReceiveReviewsAction | ReceiveReviewVoteAction | ReceiveSingleReviewAction;
12
+ /**
13
+ * Stores a collection of products by the related hash of the request parameters.
14
+ * @param state The current state.
15
+ * @param action The current redux action.
16
+ * @returns The new state.
17
+ */
18
+ declare const reviewsById: Reducer<ReviewsById, ReviewsByIdAction>;
19
+ export default reviewsById;
20
+ //# sourceMappingURL=reviewsById.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewsById.d.ts","sourceRoot":"","sources":["../../../reviews/reducers/reviewsById.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAGL,mBAAmB,EACnB,qBAAqB,EAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE5D,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,OAAO,qBAAqB,GAAG,OAAO,mBAAmB,CAAC;IAChE,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1B,CAAC;AAEF,KAAK,iBAAiB,GAClB,2BAA2B,GAC3B,oBAAoB,GACpB,uBAAuB,GACvB,yBAAyB,CAAC;AAE9B;;;;;GAKG;AACH,QAAA,MAAM,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,iBAAiB,CAyCxD,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1,12 +1,11 @@
1
- import { RECEIVE_PRODUCT_REVIEWS, RECEIVE_REVIEWS, RECEIVE_USER_REVIEW, RECEIVE_SUBMIT_REVIEW } from "../constants";
2
-
1
+ import { RECEIVE_PRODUCT_REVIEWS, RECEIVE_REVIEWS, RECEIVE_USER_REVIEW, RECEIVE_SUBMIT_REVIEW, RECEIVE_REVIEW_VOTE } from "../constants";
3
2
  /**
4
3
  * Stores a collection of products by the related hash of the request parameters.
5
- * @param {Object} [state={}] The current state.
6
- * @param {Object} action The current redux action.
7
- * @return {Object} The new state.
4
+ * @param state The current state.
5
+ * @param action The current redux action.
6
+ * @returns The new state.
8
7
  */
9
- function reviewsById(state = {}, action = {}) {
8
+ const reviewsById = (state = {}, action = {}) => {
10
9
  switch (action.type) {
11
10
  case RECEIVE_PRODUCT_REVIEWS:
12
11
  case RECEIVE_REVIEWS:
@@ -19,12 +18,29 @@ function reviewsById(state = {}, action = {}) {
19
18
  }
20
19
  case RECEIVE_SUBMIT_REVIEW:
21
20
  case RECEIVE_USER_REVIEW:
21
+ if (!action.review?.id) {
22
+ return state;
23
+ }
22
24
  return {
23
25
  ...state,
24
26
  [action.review.id]: action.review
25
27
  };
28
+ case RECEIVE_REVIEW_VOTE:
29
+ {
30
+ const review = state[action.reviewId];
31
+ if (!review) {
32
+ return state;
33
+ }
34
+ return {
35
+ ...state,
36
+ [action.reviewId]: {
37
+ ...review,
38
+ reviewVotes: action.reviewVotes
39
+ }
40
+ };
41
+ }
26
42
  default:
27
43
  return state;
28
44
  }
29
- }
45
+ };
30
46
  export default reviewsById;
@@ -0,0 +1,23 @@
1
+ import type { Reducer } from 'redux';
2
+ import { REQUEST_SUBMIT_REVIEW } from '../constants';
3
+ import type { RequestProductReviewsAction } from '../action-creators/requestProductReviews';
4
+ import type { ReceiveProductReviewsAction } from '../action-creators/receiveProductReviews';
5
+ import type { ErrorProductReviewsAction } from '../action-creators/errorProductReviews';
6
+ import type { ReviewsByProductId } from '../types/reviews';
7
+ type RequestSubmitReviewAction = {
8
+ type: typeof REQUEST_SUBMIT_REVIEW;
9
+ review: {
10
+ productId: string;
11
+ };
12
+ };
13
+ type ReviewsByProductIdAction = RequestProductReviewsAction | ReceiveProductReviewsAction | ErrorProductReviewsAction | RequestSubmitReviewAction;
14
+ /**
15
+ * Stores product reviews by their product ID.
16
+ * Responses are only applied when they belong to the latest request of a product.
17
+ * @param state The current state.
18
+ * @param action The action object.
19
+ * @returns The new state.
20
+ */
21
+ declare const reviewsByProductId: Reducer<ReviewsByProductId, ReviewsByProductIdAction>;
22
+ export default reviewsByProductId;
23
+ //# sourceMappingURL=reviewsByProductId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewsByProductId.d.ts","sourceRoot":"","sources":["../../../reviews/reducers/reviewsByProductId.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAIL,qBAAqB,EAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAC5F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,OAAO,qBAAqB,CAAC;IACnC,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,KAAK,wBAAwB,GACzB,2BAA2B,GAC3B,2BAA2B,GAC3B,yBAAyB,GACzB,yBAAyB,CAAC;AAE9B;;;;;;GAMG;AACH,QAAA,MAAM,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,EAAE,wBAAwB,CA+D7E,CAAC;AAEF,eAAe,kBAAkB,CAAC"}